From: Peter Zijlstra <a.p.zijlstra@chello.nl>
To: mingo@elte.hu, Linus Torvalds <torvalds@osdl.org>
Cc: linux-kernel@vger.kernel.org,
Stephane Eranian <eranian@google.com>,
Peter Zijlstra <a.p.zijlstra@chello.nl>
Subject: [RFC,PATCH 2/2] perf, x86: Utilize the LBRs for machine/oops debugging
Date: Mon, 29 Mar 2010 14:20:23 +0200 [thread overview]
Message-ID: <20100329122138.848413757@chello.nl> (raw)
In-Reply-To: 20100329122021.765109681@chello.nl
[-- Attachment #1: perf-lbr-debug.patch --]
[-- Type: text/plain, Size: 5414 bytes --]
The LBRs are relatively cheap to keep enabled and provide some history
to OOPSen, also some CPUs are reported to keep them over soft-reset,
which allows us to use them to debug things like tripple faults.
Therefore introduce a boot option: lbr_debug=on, which always enable
the LBRs and will print the LBRs on CPU init and die().
Requested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
---
arch/x86/include/asm/perf_event.h | 7 ++
arch/x86/kernel/cpu/perf_event_intel.c | 5 -
arch/x86/kernel/cpu/perf_event_intel_lbr.c | 86 +++++++++++++++++++++++++++--
arch/x86/kernel/dumpstack.c | 5 +
4 files changed, 95 insertions(+), 8 deletions(-)
Index: linux-2.6/arch/x86/include/asm/perf_event.h
===================================================================
--- linux-2.6.orig/arch/x86/include/asm/perf_event.h
+++ linux-2.6/arch/x86/include/asm/perf_event.h
@@ -155,9 +155,14 @@ extern void perf_events_lapic_init(void)
#define perf_instruction_pointer(regs) ((regs)->ip)
+void dump_lbr_state(void);
+void lbr_off(void);
+
#else
static inline void init_hw_perf_events(void) { }
-static inline void perf_events_lapic_init(void) { }
+static inline void perf_events_lapic_init(void) { }
+static inline void dump_lbr_state(void) { }
+static inline void lbr_off(void) { }
#endif
#endif /* _ASM_X86_PERF_EVENT_H */
Index: linux-2.6/arch/x86/kernel/cpu/perf_event_intel.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/cpu/perf_event_intel.c
+++ linux-2.6/arch/x86/kernel/cpu/perf_event_intel.c
@@ -804,10 +804,7 @@ static __initconst const struct x86_pmu
static void intel_pmu_cpu_starting(int cpu)
{
init_debug_store_on_cpu(cpu);
- /*
- * Deal with CPUs that don't clear their LBRs on power-up.
- */
- intel_pmu_lbr_reset();
+ intel_pmu_lbr_starting();
}
static void intel_pmu_cpu_dying(int cpu)
Index: linux-2.6/arch/x86/kernel/cpu/perf_event_intel_lbr.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/cpu/perf_event_intel_lbr.c
+++ linux-2.6/arch/x86/kernel/cpu/perf_event_intel_lbr.c
@@ -1,12 +1,32 @@
#ifdef CONFIG_CPU_SUP_INTEL
enum {
+ LBR_DEBUG_OFF = 0,
+ LBR_DEBUG_ON = 1,
+};
+
+static int lbr_debug_state __read_mostly;
+
+static int __init setup_lbr_debug(char *str)
+{
+ if (!strcmp(str, "on"))
+ lbr_debug_state = LBR_DEBUG_ON;
+ else
+ return 0;
+ return 1;
+}
+
+__setup("lbr_debug=", setup_lbr_debug);
+
+enum {
LBR_FORMAT_32 = 0x00,
LBR_FORMAT_LIP = 0x01,
LBR_FORMAT_EIP = 0x02,
LBR_FORMAT_EIP_FLAGS = 0x03,
};
+static DEFINE_PER_CPU(int, lbr_print_done);
+
/*
* We only support LBR implementations that have FREEZE_LBRS_ON_PMI
* otherwise it becomes near impossible to get a reliable stack.
@@ -50,9 +70,6 @@ static void intel_pmu_lbr_reset_64(void)
static void intel_pmu_lbr_reset(void)
{
- if (!x86_pmu.lbr_nr)
- return;
-
if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_32)
intel_pmu_lbr_reset_32();
else
@@ -182,6 +199,8 @@ static void intel_pmu_lbr_read(void)
{
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+ cpuc->lbr_stack.nr = 0;
+
if (!cpuc->lbr_users)
return;
@@ -215,4 +234,65 @@ static void intel_pmu_lbr_init_atom(void
x86_pmu.lbr_to = 0x60;
}
+static void __dump_lbr_state(void)
+{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+ int i;
+
+ intel_pmu_lbr_read();
+ for (i = 0; i < cpuc->lbr_stack.nr; i++) {
+ printk(KERN_DEBUG "CPU%d LBR%d: %pF -> %pF\n",
+ smp_processor_id(), i,
+ (void *)cpuc->lbr_entries[i].from,
+ (void *)cpuc->lbr_entries[i].to);
+ }
+}
+
+static void intel_pmu_lbr_starting(void)
+{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+ if (!x86_pmu.lbr_nr)
+ return;
+
+ cpuc->lbr_users = 1;
+ if (lbr_debug_state && !__get_cpu_var(lbr_print_done)) {
+ __get_cpu_var(lbr_print_done) = 1;
+ __dump_lbr_state();
+ }
+
+ intel_pmu_lbr_reset();
+
+ if (lbr_debug_state)
+ __intel_pmu_lbr_enable();
+ else
+ cpuc->lbr_users = 0;
+}
+
+void dump_lbr_state(void)
+{
+ if (!lbr_debug_state)
+ return;
+
+ __dump_lbr_state();
+}
+
+void lbr_off(void)
+{
+ if (!lbr_debug_state)
+ return;
+
+ __intel_pmu_lbr_disable();
+}
+
+#else
+
+void dump_lbr_state(void)
+{
+}
+
+void lbr_off(void)
+{
+}
+
#endif /* CONFIG_CPU_SUP_INTEL */
Index: linux-2.6/arch/x86/kernel/dumpstack.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/dumpstack.c
+++ linux-2.6/arch/x86/kernel/dumpstack.c
@@ -17,6 +17,7 @@
#include <linux/sysfs.h>
#include <asm/stacktrace.h>
+#include <asm/perf_event.h>
#include "dumpstack.h"
@@ -224,6 +225,8 @@ unsigned __kprobes long oops_begin(void)
int cpu;
unsigned long flags;
+ lbr_off();
+
oops_enter();
/* racy, but better than risking deadlock. */
@@ -306,6 +309,7 @@ int __kprobes __die(const char *str, str
printk_address(regs->ip, 1);
printk(" RSP <%016lx>\n", regs->sp);
#endif
+ dump_lbr_state();
return 0;
}
@@ -343,6 +347,7 @@ die_nmi(char *str, struct pt_regs *regs,
printk(" on CPU%d, ip %08lx, registers:\n",
smp_processor_id(), regs->ip);
show_registers(regs);
+ dump_lbr_state();
oops_end(flags, regs, 0);
if (do_panic || panic_on_oops)
panic("Non maskable interrupt");
next prev parent reply other threads:[~2010-03-29 12:25 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-03-29 12:20 [PATCH 0/2] perf: Use LBR for machine/oops debugging Peter Zijlstra
2010-03-29 12:20 ` [PATCH 1/2] perf, x86: fix __initconst vs const Peter Zijlstra
2010-03-29 12:20 ` Peter Zijlstra [this message]
2010-03-29 12:47 ` [RFC,PATCH 2/2] perf, x86: Utilize the LBRs for machine/oops debugging Stephane Eranian
2010-03-29 14:13 ` Peter Zijlstra
2010-03-29 14:20 ` Stephane Eranian
2010-03-29 17:02 ` Ingo Molnar
2010-03-29 17:12 ` Peter Zijlstra
2010-04-02 20:44 ` Ingo Molnar
2010-03-29 13:08 ` [PATCH 0/2] perf: Use LBR " Andi Kleen
2010-03-29 13:16 ` Stephane Eranian
2010-03-29 14:14 ` Peter Zijlstra
2010-03-29 20:09 ` Andi Kleen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100329122138.848413757@chello.nl \
--to=a.p.zijlstra@chello.nl \
--cc=eranian@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=torvalds@osdl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.