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 /kernel/trace/trace_hw_branches.c | |
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>
Diffstat (limited to 'kernel/trace/trace_hw_branches.c')
-rw-r--r-- | kernel/trace/trace_hw_branches.c | 29 |
1 files changed, 22 insertions, 7 deletions
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", |