aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_functions_graph.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r--kernel/trace/trace_functions_graph.c635
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
17struct 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
24static struct tracer_opt trace_opts[] = { 32static 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
36static struct tracer_flags tracer_flags = { 48static 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 */
43static pid_t last_pid[NR_CPUS] = { [0 ... NR_CPUS-1] = -1 };
44 56
45static int graph_trace_init(struct trace_array *tr) 57
58/* Add a function return address to the trace stack on thread info.*/
59int
60ftrace_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(&current->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.*/
87void
88ftrace_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(&current->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 */
116unsigned 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
135static 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)
112static enum print_line_t 197static enum print_line_t
113print_graph_proc(struct trace_seq *s, pid_t pid) 198print_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 */
155static enum print_line_t 240static enum print_line_t
156verif_pid(struct trace_seq *s, pid_t pid, int cpu) 241verif_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 (!<