diff options
-rw-r--r-- | kernel/trace/Kconfig | 9 | ||||
-rw-r--r-- | kernel/trace/Makefile | 1 | ||||
-rw-r--r-- | kernel/trace/trace.c | 3 | ||||
-rw-r--r-- | kernel/trace/trace.h | 3 | ||||
-rw-r--r-- | kernel/trace/trace_selftest.c | 32 | ||||
-rw-r--r-- | kernel/trace/trace_sysprof.c | 330 |
6 files changed, 0 insertions, 378 deletions
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index f5306cb0afb1..c7683fd8a03a 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig | |||
@@ -194,15 +194,6 @@ config PREEMPT_TRACER | |||
194 | enabled. This option and the irqs-off timing option can be | 194 | enabled. This option and the irqs-off timing option can be |
195 | used together or separately.) | 195 | used together or separately.) |
196 | 196 | ||
197 | config SYSPROF_TRACER | ||
198 | bool "Sysprof Tracer" | ||
199 | depends on X86 | ||
200 | select GENERIC_TRACER | ||
201 | select CONTEXT_SWITCH_TRACER | ||
202 | help | ||
203 | This tracer provides the trace needed by the 'Sysprof' userspace | ||
204 | tool. | ||
205 | |||
206 | config SCHED_TRACER | 197 | config SCHED_TRACER |
207 | bool "Scheduling Latency Tracer" | 198 | bool "Scheduling Latency Tracer" |
208 | select GENERIC_TRACER | 199 | select GENERIC_TRACER |
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index 84b2c9908dae..438e84a56ab3 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile | |||
@@ -30,7 +30,6 @@ obj-$(CONFIG_TRACING) += trace_output.o | |||
30 | obj-$(CONFIG_TRACING) += trace_stat.o | 30 | obj-$(CONFIG_TRACING) += trace_stat.o |
31 | obj-$(CONFIG_TRACING) += trace_printk.o | 31 | obj-$(CONFIG_TRACING) += trace_printk.o |
32 | obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o | 32 | obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o |
33 | obj-$(CONFIG_SYSPROF_TRACER) += trace_sysprof.o | ||
34 | obj-$(CONFIG_FUNCTION_TRACER) += trace_functions.o | 33 | obj-$(CONFIG_FUNCTION_TRACER) += trace_functions.o |
35 | obj-$(CONFIG_IRQSOFF_TRACER) += trace_irqsoff.o | 34 | obj-$(CONFIG_IRQSOFF_TRACER) += trace_irqsoff.o |
36 | obj-$(CONFIG_PREEMPT_TRACER) += trace_irqsoff.o | 35 | obj-$(CONFIG_PREEMPT_TRACER) += trace_irqsoff.o |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 8683dec6946b..78a49e67f7db 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -4354,9 +4354,6 @@ static __init int tracer_init_debugfs(void) | |||
4354 | trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, | 4354 | trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, |
4355 | &ftrace_update_tot_cnt, &tracing_dyn_info_fops); | 4355 | &ftrace_update_tot_cnt, &tracing_dyn_info_fops); |
4356 | #endif | 4356 | #endif |
4357 | #ifdef CONFIG_SYSPROF_TRACER | ||
4358 | init_tracer_sysprof_debugfs(d_tracer); | ||
4359 | #endif | ||
4360 | 4357 | ||
4361 | create_trace_options_dir(); | 4358 | create_trace_options_dir(); |
4362 | 4359 | ||
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 84d3f123e86f..2114b4c1150f 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -296,7 +296,6 @@ struct dentry *trace_create_file(const char *name, | |||
296 | const struct file_operations *fops); | 296 | const struct file_operations *fops); |
297 | 297 | ||
298 | struct dentry *tracing_init_dentry(void); | 298 | struct dentry *tracing_init_dentry(void); |
299 | void init_tracer_sysprof_debugfs(struct dentry *d_tracer); | ||
300 | 299 | ||
301 | struct ring_buffer_event; | 300 | struct ring_buffer_event; |
302 | 301 | ||
@@ -428,8 +427,6 @@ extern int trace_selftest_startup_nop(struct tracer *trace, | |||
428 | struct trace_array *tr); | 427 | struct trace_array *tr); |
429 | extern int trace_selftest_startup_sched_switch(struct tracer *trace, | 428 | extern int trace_selftest_startup_sched_switch(struct tracer *trace, |
430 | struct trace_array *tr); | 429 | struct trace_array *tr); |
431 | extern int trace_selftest_startup_sysprof(struct tracer *trace, | ||
432 | struct trace_array *tr); | ||
433 | extern int trace_selftest_startup_branch(struct tracer *trace, | 430 | extern int trace_selftest_startup_branch(struct tracer *trace, |
434 | struct trace_array *tr); | 431 | struct trace_array *tr); |
435 | #endif /* CONFIG_FTRACE_STARTUP_TEST */ | 432 | #endif /* CONFIG_FTRACE_STARTUP_TEST */ |
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 39a5ca4cf15b..6ed05ee6cbc7 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c | |||
@@ -690,38 +690,6 @@ trace_selftest_startup_sched_switch(struct tracer *trace, struct trace_array *tr | |||
690 | } | 690 | } |
691 | #endif /* CONFIG_CONTEXT_SWITCH_TRACER */ | 691 | #endif /* CONFIG_CONTEXT_SWITCH_TRACER */ |
692 | 692 | ||
693 | #ifdef CONFIG_SYSPROF_TRACER | ||
694 | int | ||
695 | trace_selftest_startup_sysprof(struct tracer *trace, struct trace_array *tr) | ||
696 | { | ||
697 | unsigned long count; | ||
698 | int ret; | ||
699 | |||
700 | /* start the tracing */ | ||
701 | ret = tracer_init(trace, tr); | ||
702 | if (ret) { | ||
703 | warn_failed_init_tracer(trace, ret); | ||
704 | return ret; | ||
705 | } | ||
706 | |||
707 | /* Sleep for a 1/10 of a second */ | ||
708 | msleep(100); | ||
709 | /* stop the tracing. */ | ||
710 | tracing_stop(); | ||
711 | /* check the trace buffer */ | ||
712 | ret = trace_test_buffer(tr, &count); | ||
713 | trace->reset(tr); | ||
714 | tracing_start(); | ||
715 | |||
716 | if (!ret && !count) { | ||
717 | printk(KERN_CONT ".. no entries found .."); | ||
718 | ret = -1; | ||
719 | } | ||
720 | |||
721 | return ret; | ||
722 | } | ||
723 | #endif /* CONFIG_SYSPROF_TRACER */ | ||
724 | |||
725 | #ifdef CONFIG_BRANCH_TRACER | 693 | #ifdef CONFIG_BRANCH_TRACER |
726 | int | 694 | int |
727 | trace_selftest_startup_branch(struct tracer *trace, struct trace_array *tr) | 695 | trace_selftest_startup_branch(struct tracer *trace, struct trace_array *tr) |
diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c deleted file mode 100644 index c080956f4d8e..000000000000 --- a/kernel/trace/trace_sysprof.c +++ /dev/null | |||
@@ -1,330 +0,0 @@ | |||
1 | /* | ||
2 | * trace stack traces | ||
3 | * | ||
4 | * Copyright (C) 2004-2008, Soeren Sandmann | ||
5 | * Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com> | ||
6 | * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com> | ||
7 | */ | ||
8 | #include <linux/kallsyms.h> | ||
9 | #include <linux/debugfs.h> | ||
10 | #include <linux/hrtimer.h> | ||
11 | #include <linux/uaccess.h> | ||
12 | #include <linux/ftrace.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/irq.h> | ||
15 | #include <linux/fs.h> | ||
16 | |||
17 | #include <asm/stacktrace.h> | ||
18 | |||
19 | #include "trace.h" | ||
20 | |||
21 | static struct trace_array *sysprof_trace; | ||
22 | static int __read_mostly tracer_enabled; | ||
23 | |||
24 | /* | ||
25 | * 1 msec sample interval by default: | ||
26 | */ | ||
27 | static unsigned long sample_period = 1000000; | ||
28 | static const unsigned int sample_max_depth = 512; | ||
29 | |||
30 | static DEFINE_MUTEX(sample_timer_lock); | ||
31 | /* | ||
32 | * Per CPU hrtimers that do the profiling: | ||
33 | */ | ||
34 | static DEFINE_PER_CPU(struct hrtimer, stack_trace_hrtimer); | ||
35 | |||
36 | struct stack_frame_user { | ||
37 | const void __user *next_fp; | ||
38 | unsigned long return_address; | ||
39 | }; | ||
40 | |||
41 | static int | ||
42 | copy_stack_frame(const void __user *fp, struct stack_frame_user *frame) | ||
43 | { | ||
44 | int ret; | ||
45 | |||
46 | if (!access_ok(VERIFY_READ, fp, sizeof(*frame))) | ||
47 | return 0; | ||
48 | |||
49 | ret = 1; | ||
50 | pagefault_disable(); | ||
51 | if (__copy_from_user_inatomic(frame, fp, sizeof(*frame))) | ||
52 | ret = 0; | ||
53 | pagefault_enable(); | ||
54 | |||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | struct backtrace_info { | ||
59 | struct trace_array_cpu *data; | ||
60 | struct trace_array *tr; | ||
61 | int pos; | ||
62 | }; | ||
63 | |||
64 | static void | ||
65 | backtrace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
66 | { | ||
67 | /* Ignore warnings */ | ||
68 | } | ||
69 | |||
70 | static void backtrace_warning(void *data, char *msg) | ||
71 | { | ||
72 | /* Ignore warnings */ | ||
73 | } | ||
74 | |||
75 | static int backtrace_stack(void *data, char *name) | ||
76 | { | ||
77 | /* Don't bother with IRQ stacks for now */ | ||
78 | return -1; | ||
79 | } | ||
80 | |||
81 | static void backtrace_address(void *data, unsigned long addr, int reliable) | ||
82 | { | ||
83 | struct backtrace_info *info = data; | ||
84 | |||
85 | if (info->pos < sample_max_depth && reliable) { | ||
86 | __trace_special(info->tr, info->data, 1, addr, 0); | ||
87 | |||
88 | info->pos++; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | static const struct stacktrace_ops backtrace_ops = { | ||
93 | .warning = backtrace_warning, | ||
94 | .warning_symbol = backtrace_warning_symbol, | ||
95 | .stack = backtrace_stack, | ||
96 | .address = backtrace_address, | ||
97 | .walk_stack = print_context_stack, | ||
98 | }; | ||
99 | |||
100 | static int | ||
101 | trace_kernel(struct pt_regs *regs, struct trace_array *tr, | ||
102 | struct trace_array_cpu *data) | ||
103 | { | ||
104 | struct backtrace_info info; | ||
105 | unsigned long bp; | ||
106 | char *stack; | ||
107 | |||
108 | info.tr = tr; | ||
109 | info.data = data; | ||
110 | info.pos = 1; | ||
111 | |||
112 | __trace_special(info.tr, info.data, 1, regs->ip, 0); | ||
113 | |||
114 | stack = ((char *)regs + sizeof(struct pt_regs)); | ||
115 | #ifdef CONFIG_FRAME_POINTER | ||
116 | bp = regs->bp; | ||
117 | #else | ||
118 | bp = 0; | ||
119 | #endif | ||
120 | |||
121 | dump_trace(NULL, regs, (void *)stack, bp, &backtrace_ops, &info); | ||
122 | |||
123 | return info.pos; | ||
124 | } | ||
125 | |||
126 | static void timer_notify(struct pt_regs *regs, int cpu) | ||
127 | { | ||
128 | struct trace_array_cpu *data; | ||
129 | struct stack_frame_user frame; | ||
130 | struct trace_array *tr; | ||
131 | const void __user *fp; | ||
132 | int is_user; | ||
133 | int i; | ||
134 | |||
135 | if (!regs) | ||
136 | return; | ||
137 | |||
138 | tr = sysprof_trace; | ||
139 | data = tr->data[cpu]; | ||
140 | is_user = user_mode(regs); | ||
141 | |||
142 | if (!current || current->pid == 0) | ||
143 | return; | ||
144 | |||
145 | if (is_user && current->state != TASK_RUNNING) | ||
146 | return; | ||
147 | |||
148 | __trace_special(tr, data, 0, 0, current->pid); | ||
149 | |||
150 | if (!is_user) | ||
151 | i = trace_kernel(regs, tr, data); | ||
152 | else | ||
153 | i = 0; | ||
154 | |||
155 | /* | ||
156 | * Trace user stack if we are not a kernel thread | ||
157 | */ | ||
158 | if (current->mm && i < sample_max_depth) { | ||
159 | regs = (struct pt_regs *)current->thread.sp0 - 1; | ||
160 | |||
161 | fp = (void __user *)regs->bp; | ||
162 | |||
163 | __trace_special(tr, data, 2, regs->ip, 0); | ||
164 | |||
165 | while (i < sample_max_depth) { | ||
166 | frame.next_fp = NULL; | ||
167 | frame.return_address = 0; | ||
168 | if (!copy_stack_frame(fp, &frame)) | ||
169 | break; | ||
170 | if ((unsigned long)fp < regs->sp) | ||
171 | break; | ||
172 | |||
173 | __trace_special(tr, data, 2, frame.return_address, | ||
174 | (unsigned long)fp); | ||
175 | fp = frame.next_fp; | ||
176 | |||
177 | i++; | ||
178 | } | ||
179 | |||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Special trace entry if we overflow the max depth: | ||
184 | */ | ||
185 | if (i == sample_max_depth) | ||
186 | __trace_special(tr, data, -1, -1, -1); | ||
187 | |||
188 | __trace_special(tr, data, 3, current->pid, i); | ||
189 | } | ||
190 | |||
191 | static enum hrtimer_restart stack_trace_timer_fn(struct hrtimer *hrtimer) | ||
192 | { | ||
193 | /* trace here */ | ||
194 | timer_notify(get_irq_regs(), smp_processor_id()); | ||
195 | |||
196 | hrtimer_forward_now(hrtimer, ns_to_ktime(sample_period)); | ||
197 | |||
198 | return HRTIMER_RESTART; | ||
199 | } | ||
200 | |||
201 | static void start_stack_timer(void *unused) | ||
202 | { | ||
203 | struct hrtimer *hrtimer = &__get_cpu_var(stack_trace_hrtimer); | ||
204 | |||
205 | hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
206 | hrtimer->function = stack_trace_timer_fn; | ||
207 | |||
208 | hrtimer_start(hrtimer, ns_to_ktime(sample_period), | ||
209 | HRTIMER_MODE_REL_PINNED); | ||
210 | } | ||
211 | |||
212 | static void start_stack_timers(void) | ||
213 | { | ||
214 | on_each_cpu(start_stack_timer, NULL, 1); | ||
215 | } | ||
216 | |||
217 | static void stop_stack_timer(int cpu) | ||
218 | { | ||
219 | struct hrtimer *hrtimer = &per_cpu(stack_trace_hrtimer, cpu); | ||
220 | |||
221 | hrtimer_cancel(hrtimer); | ||
222 | } | ||
223 | |||
224 | static void stop_stack_timers(void) | ||
225 | { | ||
226 | int cpu; | ||
227 | |||
228 | for_each_online_cpu(cpu) | ||
229 | stop_stack_timer(cpu); | ||
230 | } | ||
231 | |||
232 | static void stop_stack_trace(struct trace_array *tr) | ||
233 | { | ||
234 | mutex_lock(&sample_timer_lock); | ||
235 | stop_stack_timers(); | ||
236 | tracer_enabled = 0; | ||
237 | mutex_unlock(&sample_timer_lock); | ||
238 | } | ||
239 | |||
240 | static int stack_trace_init(struct trace_array *tr) | ||
241 | { | ||
242 | sysprof_trace = tr; | ||
243 | |||
244 | tracing_start_cmdline_record(); | ||
245 | |||
246 | mutex_lock(&sample_timer_lock); | ||
247 | start_stack_timers(); | ||
248 | tracer_enabled = 1; | ||
249 | mutex_unlock(&sample_timer_lock); | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static void stack_trace_reset(struct trace_array *tr) | ||
254 | { | ||
255 | tracing_stop_cmdline_record(); | ||
256 | stop_stack_trace(tr); | ||
257 | } | ||
258 | |||
259 | static struct tracer stack_trace __read_mostly = | ||
260 | { | ||
261 | .name = "sysprof", | ||
262 | .init = stack_trace_init, | ||
263 | .reset = stack_trace_reset, | ||
264 | #ifdef CONFIG_FTRACE_SELFTEST | ||
265 | .selftest = trace_selftest_startup_sysprof, | ||
266 | #endif | ||
267 | }; | ||
268 | |||
269 | __init static int init_stack_trace(void) | ||
270 | { | ||
271 | return register_tracer(&stack_trace); | ||
272 | } | ||
273 | device_initcall(init_stack_trace); | ||
274 | |||
275 | #define MAX_LONG_DIGITS 22 | ||
276 | |||
277 | static ssize_t | ||
278 | sysprof_sample_read(struct file *filp, char __user *ubuf, | ||
279 | size_t cnt, loff_t *ppos) | ||
280 | { | ||
281 | char buf[MAX_LONG_DIGITS]; | ||
282 | int r; | ||
283 | |||
284 | r = sprintf(buf, "%ld\n", nsecs_to_usecs(sample_period)); | ||
285 | |||
286 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | ||
287 | } | ||
288 | |||
289 | static ssize_t | ||
290 | sysprof_sample_write(struct file *filp, const char __user *ubuf, | ||
291 | size_t cnt, loff_t *ppos) | ||
292 | { | ||
293 | char buf[MAX_LONG_DIGITS]; | ||
294 | unsigned long val; | ||
295 | |||
296 | if (cnt > MAX_LONG_DIGITS-1) | ||
297 | cnt = MAX_LONG_DIGITS-1; | ||
298 | |||
299 | if (copy_from_user(&buf, ubuf, cnt)) | ||
300 | return -EFAULT; | ||
301 | |||
302 | buf[cnt] = 0; | ||
303 | |||
304 | val = simple_strtoul(buf, NULL, 10); | ||
305 | /* | ||
306 | * Enforce a minimum sample period of 100 usecs: | ||
307 | */ | ||
308 | if (val < 100) | ||
309 | val = 100; | ||
310 | |||
311 | mutex_lock(&sample_timer_lock); | ||
312 | stop_stack_timers(); | ||
313 | sample_period = val * 1000; | ||
314 | start_stack_timers(); | ||
315 | mutex_unlock(&sample_timer_lock); | ||
316 | |||
317 | return cnt; | ||
318 | } | ||
319 | |||
320 | static const struct file_operations sysprof_sample_fops = { | ||
321 | .read = sysprof_sample_read, | ||
322 | .write = sysprof_sample_write, | ||
323 | }; | ||
324 | |||
325 | void init_tracer_sysprof_debugfs(struct dentry *d_tracer) | ||
326 | { | ||
327 | |||
328 | trace_create_file("sysprof_sample_period", 0644, | ||
329 | d_tracer, NULL, &sysprof_sample_fops); | ||
330 | } | ||