diff options
author | Markus Metzger <markus.t.metzger@intel.com> | 2009-01-19 04:31:01 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-01-20 07:03:48 -0500 |
commit | b1818748b0cf9427e48acf9713295e829a0d715f (patch) | |
tree | 49e8f8dc4328799fa69eae635f4b69ee97228445 | |
parent | 5c5317de147e9b38ea9c4cbdc2d15bed7648d036 (diff) |
x86, ftrace, hw-branch-tracer: dump trace on oops
Dump the branch trace on an oops (based on ftrace_dump_on_oops).
Signed-off-by: Markus Metzger <markus.t.metzger@intel.com>
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/kernel/dumpstack.c | 6 | ||||
-rw-r--r-- | include/linux/ftrace.h | 13 | ||||
-rw-r--r-- | kernel/trace/trace.h | 1 | ||||
-rw-r--r-- | kernel/trace/trace_hw_branches.c | 29 |
4 files changed, 41 insertions, 8 deletions
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 6b1f6f6f8661..077c9ea655fc 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/bug.h> | 14 | #include <linux/bug.h> |
15 | #include <linux/nmi.h> | 15 | #include <linux/nmi.h> |
16 | #include <linux/sysfs.h> | 16 | #include <linux/sysfs.h> |
17 | #include <linux/ftrace.h> | ||
17 | 18 | ||
18 | #include <asm/stacktrace.h> | 19 | #include <asm/stacktrace.h> |
19 | 20 | ||
@@ -195,6 +196,11 @@ unsigned __kprobes long oops_begin(void) | |||
195 | int cpu; | 196 | int cpu; |
196 | unsigned long flags; | 197 | unsigned long flags; |
197 | 198 | ||
199 | /* notify the hw-branch tracer so it may disable tracing and | ||
200 | add the last trace to the trace buffer - | ||
201 | the earlier this happens, the more useful the trace. */ | ||
202 | trace_hw_branch_oops(); | ||
203 | |||
198 | oops_enter(); | 204 | oops_enter(); |
199 | 205 | ||
200 | /* racy, but better than risking deadlock. */ | 206 | /* racy, but better than risking deadlock. */ |
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 054721487574..9f7880d87c39 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -496,4 +496,17 @@ static inline int test_tsk_trace_graph(struct task_struct *tsk) | |||
496 | 496 | ||
497 | #endif /* CONFIG_TRACING */ | 497 | #endif /* CONFIG_TRACING */ |
498 | 498 | ||
499 | |||
500 | #ifdef CONFIG_HW_BRANCH_TRACER | ||
501 | |||
502 | void trace_hw_branch(u64 from, u64 to); | ||
503 | void trace_hw_branch_oops(void); | ||
504 | |||
505 | #else /* CONFIG_HW_BRANCH_TRACER */ | ||
506 | |||
507 | static inline void trace_hw_branch(u64 from, u64 to) {} | ||
508 | static inline void trace_hw_branch_oops(void) {} | ||
509 | |||
510 | #endif /* CONFIG_HW_BRANCH_TRACER */ | ||
511 | |||
499 | #endif /* _LINUX_FTRACE_H */ | 512 | #endif /* _LINUX_FTRACE_H */ |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 54b72781e920..b96037d970df 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -438,7 +438,6 @@ void trace_function(struct trace_array *tr, | |||
438 | 438 | ||
439 | void trace_graph_return(struct ftrace_graph_ret *trace); | 439 | void trace_graph_return(struct ftrace_graph_ret *trace); |
440 | int trace_graph_entry(struct ftrace_graph_ent *trace); | 440 | int trace_graph_entry(struct ftrace_graph_ent *trace); |
441 | void trace_hw_branch(struct trace_array *tr, u64 from, u64 to); | ||
442 | 441 | ||
443 | void tracing_start_cmdline_record(void); | 442 | void tracing_start_cmdline_record(void); |
444 | void tracing_stop_cmdline_record(void); | 443 | void tracing_stop_cmdline_record(void); |
diff --git a/kernel/trace/trace_hw_branches.c b/kernel/trace/trace_hw_branches.c index 398195397c75..e56df2c7d679 100644 --- a/kernel/trace/trace_hw_branches.c +++ b/kernel/trace/trace_hw_branches.c | |||
@@ -40,6 +40,7 @@ static DEFINE_PER_CPU(unsigned char[SIZEOF_BTS], buffer); | |||
40 | #define this_buffer per_cpu(buffer, smp_processor_id()) | 40 | #define this_buffer per_cpu(buffer, smp_processor_id()) |
41 | 41 | ||
42 | static int __read_mostly trace_hw_branches_enabled; | 42 | static int __read_mostly trace_hw_branches_enabled; |
43 | static struct trace_array *hw_branch_trace __read_mostly; | ||
43 | 44 | ||
44 | 45 | ||
45 | /* | 46 | /* |
@@ -128,6 +129,8 @@ static struct notifier_block bts_hotcpu_notifier __cpuinitdata = { | |||
128 | 129 | ||
129 | static int bts_trace_init(struct trace_array *tr) | 130 | static int bts_trace_init(struct trace_array *tr) |
130 | { | 131 | { |
132 | hw_branch_trace = tr; | ||
133 | |||
131 | register_hotcpu_notifier(&bts_hotcpu_notifier); | 134 | register_hotcpu_notifier(&bts_hotcpu_notifier); |
132 | tracing_reset_online_cpus(tr); | 135 | tracing_reset_online_cpus(tr); |
133 | bts_trace_start(tr); | 136 | bts_trace_start(tr); |
@@ -170,8 +173,9 @@ static enum print_line_t bts_trace_print_line(struct trace_iterator *iter) | |||
170 | return TRACE_TYPE_UNHANDLED; | 173 | return TRACE_TYPE_UNHANDLED; |
171 | } | 174 | } |
172 | 175 | ||
173 | void trace_hw_branch(struct trace_array *tr, u64 from, u64 to) | 176 | void trace_hw_branch(u64 from, u64 to) |
174 | { | 177 | { |
178 | struct trace_array *tr = hw_branch_trace; | ||
175 | struct ring_buffer_event *event; | 179 | struct ring_buffer_event *event; |
176 | struct hw_branch_entry *entry; | 180 | struct hw_branch_entry *entry; |
177 | unsigned long irq1, irq2; | 181 | unsigned long irq1, irq2; |
@@ -204,8 +208,7 @@ void trace_hw_branch(struct trace_array *tr, u64 from, u64 to) | |||
204 | local_irq_restore(irq1); | 208 | local_irq_restore(irq1); |
205 | } | 209 | } |
206 | 210 | ||
207 | static void trace_bts_at(struct trace_array *tr, | 211 | static void trace_bts_at(const struct bts_trace *trace, void *at) |
208 | const struct bts_trace *trace, void *at) | ||
209 | { | 212 | { |
210 | struct bts_struct bts; | 213 | struct bts_struct bts; |
211 | int err = 0; | 214 | int err = 0; |
@@ -220,7 +223,7 @@ static void trace_bts_at(struct trace_array *tr, | |||
220 | 223 | ||
221 | switch (bts.qualifier) { | 224 | switch (bts.qualifier) { |
222 | case BTS_BRANCH: | 225 | case BTS_BRANCH: |
223 | trace_hw_branch(tr, bts.variant.lbr.from, bts.variant.lbr.to); | 226 | trace_hw_branch(bts.variant.lbr.from, bts.variant.lbr.to); |
224 | break; | 227 | break; |
225 | } | 228 | } |
226 | } | 229 | } |
@@ -236,12 +239,15 @@ static void trace_bts_cpu(void *arg) | |||
236 | const struct bts_trace *trace; | 239 | const struct bts_trace *trace; |
237 | unsigned char *at; | 240 | unsigned char *at; |
238 | 241 | ||
239 | if (!this_tracer) | 242 | if (unlikely(!tr)) |
240 | return; | 243 | return; |
241 | 244 | ||
242 | if (unlikely(atomic_read(&tr->data[raw_smp_processor_id()]->disabled))) | 245 | if (unlikely(atomic_read(&tr->data[raw_smp_processor_id()]->disabled))) |
243 | return; | 246 | return; |
244 | 247 | ||
248 | if (unlikely(!this_tracer)) | ||
249 | return; | ||
250 | |||
245 | ds_suspend_bts(this_tracer); | 251 | ds_suspend_bts(this_tracer); |
246 | trace = ds_read_bts(this_tracer); | 252 | trace = ds_read_bts(this_tracer); |
247 | if (!trace) | 253 | if (!trace) |
@@ -249,11 +255,11 @@ static void trace_bts_cpu(void *arg) | |||
249 | 255 | ||
250 | for (at = trace->ds.top; (void *)at < trace->ds.end; | 256 | for (at = trace->ds.top; (void *)at < trace->ds.end; |
251 | at += trace->ds.size) | 257 | at += trace->ds.size) |
252 | trace_bts_at(tr, trace, at); | 258 | trace_bts_at(trace, at); |
253 | 259 | ||
254 | for (at = trace->ds.begin; (void *)at < trace->ds.top; | 260 | for (at = trace->ds.begin; (void *)at < trace->ds.top; |
255 | at += trace->ds.size) | 261 | at += trace->ds.size) |
256 | trace_bts_at(tr, trace, at); | 262 | trace_bts_at(trace, at); |
257 | 263 | ||
258 | out: | 264 | out: |
259 | ds_resume_bts(this_tracer); | 265 | ds_resume_bts(this_tracer); |
@@ -268,6 +274,15 @@ static void trace_bts_prepare(struct trace_iterator *iter) | |||
268 | mutex_unlock(&bts_tracer_mutex); | 274 | mutex_unlock(&bts_tracer_mutex); |
269 | } | 275 | } |
270 | 276 | ||
277 | void trace_hw_branch_oops(void) | ||
278 | { | ||
279 | mutex_lock(&bts_tracer_mutex); | ||
280 | |||
281 | trace_bts_cpu(hw_branch_trace); | ||
282 | |||
283 | mutex_unlock(&bts_tracer_mutex); | ||
284 | } | ||
285 | |||
271 | struct tracer bts_tracer __read_mostly = | 286 | struct tracer bts_tracer __read_mostly = |
272 | { | 287 | { |
273 | .name = "hw-branch-tracer", | 288 | .name = "hw-branch-tracer", |