diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
| -rw-r--r-- | kernel/trace/trace_functions_graph.c | 635 |
1 files changed, 427 insertions, 208 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 930c08e5b38..d28687e7b3a 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * | 2 | * |
| 3 | * Function graph tracer. | 3 | * Function graph tracer. |
| 4 | * Copyright (c) 2008 Frederic Weisbecker <fweisbec@gmail.com> | 4 | * Copyright (c) 2008-2009 Frederic Weisbecker <fweisbec@gmail.com> |
| 5 | * Mostly borrowed from function tracer which | 5 | * Mostly borrowed from function tracer which |
| 6 | * is Copyright (c) Steven Rostedt <srostedt@redhat.com> | 6 | * is Copyright (c) Steven Rostedt <srostedt@redhat.com> |
| 7 | * | 7 | * |
| @@ -12,6 +12,12 @@ | |||
| 12 | #include <linux/fs.h> | 12 | #include <linux/fs.h> |
| 13 | 13 | ||
| 14 | #include "trace.h" | 14 | #include "trace.h" |
| 15 | #include "trace_output.h" | ||
| 16 | |||
| 17 | struct fgraph_data { | ||
| 18 | pid_t last_pid; | ||
| 19 | int depth; | ||
| 20 | }; | ||
| 15 | 21 | ||
| 16 | #define TRACE_GRAPH_INDENT 2 | 22 | #define TRACE_GRAPH_INDENT 2 |
| 17 | 23 | ||
| @@ -20,9 +26,11 @@ | |||
| 20 | #define TRACE_GRAPH_PRINT_CPU 0x2 | 26 | #define TRACE_GRAPH_PRINT_CPU 0x2 |
| 21 | #define TRACE_GRAPH_PRINT_OVERHEAD 0x4 | 27 | #define TRACE_GRAPH_PRINT_OVERHEAD 0x4 |
| 22 | #define TRACE_GRAPH_PRINT_PROC 0x8 | 28 | #define TRACE_GRAPH_PRINT_PROC 0x8 |
| 29 | #define TRACE_GRAPH_PRINT_DURATION 0x10 | ||
| 30 | #define TRACE_GRAPH_PRINT_ABS_TIME 0X20 | ||
| 23 | 31 | ||
| 24 | static struct tracer_opt trace_opts[] = { | 32 | static struct tracer_opt trace_opts[] = { |
| 25 | /* Display overruns ? */ | 33 | /* Display overruns? (for self-debug purpose) */ |
| 26 | { TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) }, | 34 | { TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) }, |
| 27 | /* Display CPU ? */ | 35 | /* Display CPU ? */ |
| 28 | { TRACER_OPT(funcgraph-cpu, TRACE_GRAPH_PRINT_CPU) }, | 36 | { TRACER_OPT(funcgraph-cpu, TRACE_GRAPH_PRINT_CPU) }, |
| @@ -30,26 +38,103 @@ static struct tracer_opt trace_opts[] = { | |||
| 30 | { TRACER_OPT(funcgraph-overhead, TRACE_GRAPH_PRINT_OVERHEAD) }, | 38 | { TRACER_OPT(funcgraph-overhead, TRACE_GRAPH_PRINT_OVERHEAD) }, |
| 31 | /* Display proc name/pid */ | 39 | /* Display proc name/pid */ |
| 32 | { TRACER_OPT(funcgraph-proc, TRACE_GRAPH_PRINT_PROC) }, | 40 | { TRACER_OPT(funcgraph-proc, TRACE_GRAPH_PRINT_PROC) }, |
| 41 | /* Display duration of execution */ | ||
| 42 | { TRACER_OPT(funcgraph-duration, TRACE_GRAPH_PRINT_DURATION) }, | ||
| 43 | /* Display absolute time of an entry */ | ||
| 44 | { TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) }, | ||
| 33 | { } /* Empty entry */ | 45 | { } /* Empty entry */ |
| 34 | }; | 46 | }; |
| 35 | 47 | ||
| 36 | static struct tracer_flags tracer_flags = { | 48 | static struct tracer_flags tracer_flags = { |
| 37 | /* Don't display overruns and proc by default */ | 49 | /* Don't display overruns and proc by default */ |
| 38 | .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD, | 50 | .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD | |
| 51 | TRACE_GRAPH_PRINT_DURATION, | ||
| 39 | .opts = trace_opts | 52 | .opts = trace_opts |
| 40 | }; | 53 | }; |
| 41 | 54 | ||
| 42 | /* pid on the last trace processed */ | 55 | /* pid on the last trace processed */ |
| 43 | static pid_t last_pid[NR_CPUS] = { [0 ... NR_CPUS-1] = -1 }; | ||
| 44 | 56 | ||
| 45 | static int graph_trace_init(struct trace_array *tr) | 57 | |
| 58 | /* Add a function return address to the trace stack on thread info.*/ | ||
| 59 | int | ||
| 60 | ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth) | ||
| 46 | { | 61 | { |
| 47 | int cpu, ret; | 62 | unsigned long long calltime; |
| 63 | int index; | ||
| 64 | |||
| 65 | if (!current->ret_stack) | ||
| 66 | return -EBUSY; | ||
| 67 | |||
| 68 | /* The return trace stack is full */ | ||
| 69 | if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) { | ||
| 70 | atomic_inc(¤t->trace_overrun); | ||
| 71 | return -EBUSY; | ||
| 72 | } | ||
| 73 | |||
| 74 | calltime = trace_clock_local(); | ||
| 75 | |||
| 76 | index = ++current->curr_ret_stack; | ||
| 77 | barrier(); | ||
| 78 | current->ret_stack[index].ret = ret; | ||
| 79 | current->ret_stack[index].func = func; | ||
| 80 | current->ret_stack[index].calltime = calltime; | ||
| 81 | *depth = index; | ||
| 82 | |||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | /* Retrieve a function return address to the trace stack on thread info.*/ | ||
| 87 | void | ||
| 88 | ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret) | ||
| 89 | { | ||
| 90 | int index; | ||
| 91 | |||
| 92 | index = current->curr_ret_stack; | ||
| 93 | |||
| 94 | if (unlikely(index < 0)) { | ||
| 95 | ftrace_graph_stop(); | ||
| 96 | WARN_ON(1); | ||
| 97 | /* Might as well panic, otherwise we have no where to go */ | ||
| 98 | *ret = (unsigned long)panic; | ||
| 99 | return; | ||
| 100 | } | ||
| 48 | 101 | ||
| 49 | for_each_online_cpu(cpu) | 102 | *ret = current->ret_stack[index].ret; |
| 50 | tracing_reset(tr, cpu); | 103 | trace->func = current->ret_stack[index].func; |
| 104 | trace->calltime = current->ret_stack[index].calltime; | ||
| 105 | trace->overrun = atomic_read(¤t->trace_overrun); | ||
| 106 | trace->depth = index; | ||
| 107 | barrier(); | ||
| 108 | current->curr_ret_stack--; | ||
| 51 | 109 | ||
| 52 | ret = register_ftrace_graph(&trace_graph_return, | 110 | } |
| 111 | |||
| 112 | /* | ||
| 113 | * Send the trace to the ring-buffer. | ||
| 114 | * @return the original return address. | ||
| 115 | */ | ||
| 116 | unsigned long ftrace_return_to_handler(void) | ||
| 117 | { | ||
| 118 | struct ftrace_graph_ret trace; | ||
| 119 | unsigned long ret; | ||
| 120 | |||
| 121 | ftrace_pop_return_trace(&trace, &ret); | ||
| 122 | trace.rettime = trace_clock_local(); | ||
| 123 | ftrace_graph_return(&trace); | ||
| 124 | |||
| 125 | if (unlikely(!ret)) { | ||
| 126 | ftrace_graph_stop(); | ||
| 127 | WARN_ON(1); | ||
| 128 | /* Might as well panic. What else to do? */ | ||
| 129 | ret = (unsigned long)panic; | ||
| 130 | } | ||
| 131 | |||
| 132 | return ret; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int graph_trace_init(struct trace_array *tr) | ||
| 136 | { | ||
| 137 | int ret = register_ftrace_graph(&trace_graph_return, | ||
| 53 | &trace_graph_entry); | 138 | &trace_graph_entry); |
| 54 | if (ret) | 139 | if (ret) |
| 55 | return ret; | 140 | return ret; |
| @@ -112,15 +197,15 @@ print_graph_cpu(struct trace_seq *s, int cpu) | |||
| 112 | static enum print_line_t | 197 | static enum print_line_t |
| 113 | print_graph_proc(struct trace_seq *s, pid_t pid) | 198 | print_graph_proc(struct trace_seq *s, pid_t pid) |
| 114 | { | 199 | { |
| 115 | int i; | 200 | char comm[TASK_COMM_LEN]; |
| 116 | int ret; | ||
| 117 | int len; | ||
| 118 | char comm[8]; | ||
| 119 | int spaces = 0; | ||
| 120 | /* sign + log10(MAX_INT) + '\0' */ | 201 | /* sign + log10(MAX_INT) + '\0' */ |
| 121 | char pid_str[11]; | 202 | char pid_str[11]; |
| 203 | int spaces = 0; | ||
| 204 | int ret; | ||
| 205 | int len; | ||
| 206 | int i; | ||
| 122 | 207 | ||
| 123 | strncpy(comm, trace_find_cmdline(pid), 7); | 208 | trace_find_cmdline(pid, comm); |
| 124 | comm[7] = '\0'; | 209 | comm[7] = '\0'; |
| 125 | sprintf(pid_str, "%d", pid); | 210 | sprintf(pid_str, "%d", pid); |
| 126 | 211 | ||
| @@ -153,17 +238,25 @@ print_graph_proc(struct trace_seq *s, pid_t pid) | |||
| 153 | 238 | ||
| 154 | /* If the pid changed since the last trace, output this event */ | 239 | /* If the pid changed since the last trace, output this event */ |
| 155 | static enum print_line_t | 240 | static enum print_line_t |
| 156 | verif_pid(struct trace_seq *s, pid_t pid, int cpu) | 241 | verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data) |
| 157 | { | 242 | { |
| 158 | pid_t prev_pid; | 243 | pid_t prev_pid; |
| 244 | pid_t *last_pid; | ||
| 159 | int ret; | 245 | int ret; |
| 160 | 246 | ||
| 161 | if (last_pid[cpu] != -1 && last_pid[cpu] == pid) | 247 | if (!< |
