2009-03-05 17:21:01

by Peter Zijlstra

[permalink] [raw]
Subject: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs

Subject: perfcounters: IRQ and NMI support on AMD CPUs
From: Peter Zijlstra <[email protected]>
Date: Thu Mar 05 18:08:27 CET 2009

The below completes the K7+ performance counter support.

Signed-off-by: Peter Zijlstra <[email protected]>
---
arch/x86/kernel/cpu/perf_counter.c | 272 +++++++++++++++++++++++++++++++------
1 file changed, 228 insertions(+), 44 deletions(-)

Index: linux-2.6/arch/x86/kernel/cpu/perf_counter.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/cpu/perf_counter.c
+++ linux-2.6/arch/x86/kernel/cpu/perf_counter.c
@@ -28,6 +28,7 @@ static bool perf_counters_initialized __
static int nr_counters_generic __read_mostly;
static u64 perf_counter_mask __read_mostly;
static u64 counter_value_mask __read_mostly;
+static int counter_value_bits __read_mostly;

static int nr_counters_fixed __read_mostly;

@@ -35,7 +36,9 @@ struct cpu_hw_counters {
struct perf_counter *counters[X86_PMC_IDX_MAX];
unsigned long used[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
unsigned long interrupts;
- u64 global_enable;
+ u64 throttle_ctrl;
+ u64 active_mask;
+ int enabled;
};

/*
@@ -43,21 +46,28 @@ struct cpu_hw_counters {
*/
struct pmc_x86_ops {
u64 (*save_disable_all)(void);
- void (*restore_all)(u64 ctrl);
+ void (*restore_all)(u64);
+ u64 (*get_status)(u64);
+ void (*ack_status)(u64);
+ void (*enable)(int, u64);
+ void (*disable)(int, u64);
unsigned eventsel;
unsigned perfctr;
- int (*event_map)(int event);
+ u64 (*event_map)(int);
+ u64 (*raw_event)(u64);
int max_events;
};

static struct pmc_x86_ops *pmc_ops;

-static DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters);
+static DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters) = {
+ .enabled = 1,
+};

/*
* Intel PerfMon v3. Used on Core2 and later.
*/
-static const int intel_perfmon_event_map[] =
+static const u64 intel_perfmon_event_map[] =
{
[PERF_COUNT_CPU_CYCLES] = 0x003c,
[PERF_COUNT_INSTRUCTIONS] = 0x00c0,
@@ -68,15 +78,29 @@ static const int intel_perfmon_event_map
[PERF_COUNT_BUS_CYCLES] = 0x013c,
};

-static int pmc_intel_event_map(int event)
+static u64 pmc_intel_event_map(int event)
{
return intel_perfmon_event_map[event];
}

+static u64 pmc_intel_raw_event(u64 event)
+{
+#define CORE_EVNTSEL_EVENT_MASK 0x000000FF
+#define CORE_EVNTSEL_UNIT_MASK 0x0000FF00
+#define CORE_EVNTSEL_COUNTER_MASK 0xFF000000
+
+#define CORE_EVNTSEL_MASK \
+ (CORE_EVNTSEL_EVENT_MASK | \
+ CORE_EVNTSEL_UNIT_MASK | \
+ CORE_EVNTSEL_COUNTER_MASK)
+
+ return event & CORE_EVNTSEL_MASK;
+}
+
/*
* AMD Performance Monitor K7 and later.
*/
-static const int amd_perfmon_event_map[] =
+static const u64 amd_perfmon_event_map[] =
{
[PERF_COUNT_CPU_CYCLES] = 0x0076,
[PERF_COUNT_INSTRUCTIONS] = 0x00c0,
@@ -86,11 +110,25 @@ static const int amd_perfmon_event_map[]
[PERF_COUNT_BRANCH_MISSES] = 0x00c5,
};

-static int pmc_amd_event_map(int event)
+static u64 pmc_amd_event_map(int event)
{
return amd_perfmon_event_map[event];
}

+static u64 pmc_amd_raw_event(u64 event)
+{
+#define K7_EVNTSEL_EVENT_MASK 0x7000000FF
+#define K7_EVNTSEL_UNIT_MASK 0x00000FF00
+#define K7_EVNTSEL_COUNTER_MASK 0x0FF000000
+
+#define K7_EVNTSEL_MASK \
+ (K7_EVNTSEL_EVENT_MASK | \
+ K7_EVNTSEL_UNIT_MASK | \
+ K7_EVNTSEL_COUNTER_MASK)
+
+ return event & K7_EVNTSEL_MASK;
+}
+
/*
* Propagate counter elapsed time into the generic counter.
* Can only be executed on the CPU where the counter is active.
@@ -179,7 +217,7 @@ static int __hw_perf_counter_init(struct
* Raw event type provide the config in the event structure
*/
if (hw_event->raw) {
- hwc->config |= hw_event->type;
+ hwc->config |= pmc_ops->raw_event(hw_event->type);
} else {
if (hw_event->type >= pmc_ops->max_events)
return -EINVAL;
@@ -205,18 +243,24 @@ static u64 pmc_intel_save_disable_all(vo

static u64 pmc_amd_save_disable_all(void)
{
- int idx;
- u64 val, ctrl = 0;
+ struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+ int enabled, idx;
+
+ enabled = cpuc->enabled;
+ cpuc->enabled = 0;
+ barrier();

for (idx = 0; idx < nr_counters_generic; idx++) {
+ u64 val;
+
rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
- if (val & ARCH_PERFMON_EVENTSEL0_ENABLE)
- ctrl |= (1 << idx);
- val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
- wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
+ if (val & ARCH_PERFMON_EVENTSEL0_ENABLE) {
+ val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
+ wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
+ }
}

- return ctrl;
+ return enabled;
}

u64 hw_perf_save_disable(void)
@@ -226,6 +270,9 @@ u64 hw_perf_save_disable(void)

return pmc_ops->save_disable_all();
}
+/*
+ * Exported because of ACPI idle
+ */
EXPORT_SYMBOL_GPL(hw_perf_save_disable);

static void pmc_intel_restore_all(u64 ctrl)
@@ -235,11 +282,18 @@ static void pmc_intel_restore_all(u64 ct

static void pmc_amd_restore_all(u64 ctrl)
{
- u64 val;
+ struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
int idx;

+ cpuc->enabled = ctrl;
+ barrier();
+ if (!ctrl)
+ return;
+
for (idx = 0; idx < nr_counters_generic; idx++) {
- if (ctrl & (1 << idx)) {
+ if (test_bit(idx, (unsigned long *)&cpuc->active_mask)) {
+ u64 val;
+
rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
@@ -254,8 +308,112 @@ void hw_perf_restore(u64 ctrl)

pmc_ops->restore_all(ctrl);
}
+/*
+ * Exported because of ACPI idle
+ */
EXPORT_SYMBOL_GPL(hw_perf_restore);

+static u64 pmc_intel_get_status(u64 mask)
+{
+ u64 status;
+
+ rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
+
+ return status;
+}
+
+static u64 pmc_amd_get_status(u64 mask)
+{
+ u64 status = 0;
+ int idx;
+
+ for (idx = 0; idx < nr_counters_generic; idx++) {
+ s64 val;
+
+ if (!(mask & (1 << idx)))
+ continue;
+
+ rdmsrl(MSR_K7_PERFCTR0 + idx, val);
+ val <<= (64 - counter_value_bits);
+ if (val >= 0)
+ status |= (1 << idx);
+ }
+
+ return status;
+}
+
+static u64 hw_perf_get_status(u64 mask)
+{
+ if (unlikely(!perf_counters_initialized))
+ return 0;
+
+ return pmc_ops->get_status(mask);
+}
+
+static void pmc_intel_ack_status(u64 ack)
+{
+ wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, ack);
+}
+
+static void pmc_amd_ack_status(u64 ack)
+{
+}
+
+static void hw_perf_ack_status(u64 ack)
+{
+ if (unlikely(!perf_counters_initialized))
+ return;
+
+ pmc_ops->ack_status(ack);
+}
+
+static void pmc_intel_enable(int idx, u64 config)
+{
+ wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + idx,
+ config | ARCH_PERFMON_EVENTSEL0_ENABLE);
+}
+
+static void pmc_amd_enable(int idx, u64 config)
+{
+ struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+
+ set_bit(idx, (unsigned long *)&cpuc->active_mask);
+ if (cpuc->enabled)
+ config |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+
+ wrmsrl(MSR_K7_EVNTSEL0 + idx, config);
+}
+
+static void hw_perf_enable(int idx, u64 config)
+{
+ if (unlikely(!perf_counters_initialized))
+ return;
+
+ pmc_ops->enable(idx, config);
+}
+
+static void pmc_intel_disable(int idx, u64 config)
+{
+ wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + idx, config);
+}
+
+static void pmc_amd_disable(int idx, u64 config)
+{
+ struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+
+ clear_bit(idx, (unsigned long *)&cpuc->active_mask);
+ wrmsrl(MSR_K7_EVNTSEL0 + idx, config);
+
+}
+
+static void hw_perf_disable(int idx, u64 config)
+{
+ if (unlikely(!perf_counters_initialized))
+ return;
+
+ pmc_ops->disable(idx, config);
+}
+
static inline void
__pmc_fixed_disable(struct perf_counter *counter,
struct hw_perf_counter *hwc, unsigned int __idx)
@@ -278,7 +436,7 @@ __pmc_generic_disable(struct perf_counte
if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL))
__pmc_fixed_disable(counter, hwc, idx);
else
- wrmsr_safe(hwc->config_base + idx, hwc->config, 0);
+ hw_perf_disable(idx, hwc->config);
}

static DEFINE_PER_CPU(u64, prev_left[X86_PMC_IDX_MAX]);
@@ -354,8 +512,7 @@ __pmc_generic_enable(struct perf_counter
if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL))
__pmc_fixed_enable(counter, hwc, idx);
else
- wrmsr(hwc->config_base + idx,
- hwc->config | ARCH_PERFMON_EVENTSEL0_ENABLE, 0);
+ hw_perf_enable(idx, hwc->config);
}

static int
@@ -567,22 +724,20 @@ perf_handle_group(struct perf_counter *s
* This handler is triggered by the local APIC, so the APIC IRQ handling
* rules apply:
*/
-static void __smp_perf_counter_interrupt(struct pt_regs *regs, int nmi)
+static int __smp_perf_counter_interrupt(struct pt_regs *regs, int nmi)
{
int bit, cpu = smp_processor_id();
u64 ack, status;
struct cpu_hw_counters *cpuc = &per_cpu(cpu_hw_counters, cpu);
+ int ret = 0;

- rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, cpuc->global_enable);
+ cpuc->throttle_ctrl = hw_perf_save_disable();

- /* Disable counters globally */
- wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
- ack_APIC_irq();
-
- rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
+ status = hw_perf_get_status(cpuc->throttle_ctrl);
if (!status)
goto out;

+ ret = 1;
again:
inc_irq_stat(apic_perf_irqs);
ack = status;
@@ -618,12 +773,12 @@ again:
}
}

- wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, ack);
+ hw_perf_ack_status(ack);

/*
* Repeat if there is more work to be done:
*/
- rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
+ status = hw_perf_get_status(cpuc->throttle_ctrl);
if (status)
goto again;
out:
@@ -631,32 +786,27 @@ out:
* Restore - do not reenable when global enable is off or throttled:
*/
if (++cpuc->interrupts < PERFMON_MAX_INTERRUPTS)
- wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, cpuc->global_enable);
+ hw_perf_restore(cpuc->throttle_ctrl);
+
+ return ret;
}

void perf_counter_unthrottle(void)
{
struct cpu_hw_counters *cpuc;
- u64 global_enable;

if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
return;

- if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
- return;
-
if (unlikely(!perf_counters_initialized))
return;

- cpuc = &per_cpu(cpu_hw_counters, smp_processor_id());
+ cpuc = &__get_cpu_var(cpu_hw_counters);
if (cpuc->interrupts >= PERFMON_MAX_INTERRUPTS) {
if (printk_ratelimit())
printk(KERN_WARNING "PERFMON: max interrupts exceeded!\n");
- wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, cpuc->global_enable);
+ hw_perf_restore(cpuc->throttle_ctrl);
}
- rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, global_enable);
- if (unlikely(cpuc->global_enable && !global_enable))
- wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, cpuc->global_enable);
cpuc->interrupts = 0;
}

@@ -664,8 +814,8 @@ void smp_perf_counter_interrupt(struct p
{
irq_enter();
apic_write(APIC_LVTPC, LOCAL_PERF_VECTOR);
+ ack_APIC_irq();
__smp_perf_counter_interrupt(regs, 0);
-
irq_exit();
}

@@ -722,16 +872,23 @@ perf_counter_nmi_handler(struct notifier
{
struct die_args *args = __args;
struct pt_regs *regs;
+ int ret;
+
+ switch (cmd) {
+ case DIE_NMI:
+ case DIE_NMI_IPI:
+ break;

- if (likely(cmd != DIE_NMI_IPI))
+ default:
return NOTIFY_DONE;
+ }

regs = args->regs;

apic_write(APIC_LVTPC, APIC_DM_NMI);
- __smp_perf_counter_interrupt(regs, 1);
+ ret = __smp_perf_counter_interrupt(regs, 1);

- return NOTIFY_STOP;
+ return ret ? NOTIFY_STOP : NOTIFY_OK;
}

static __read_mostly struct notifier_block perf_counter_nmi_notifier = {
@@ -743,18 +900,28 @@ static __read_mostly struct notifier_blo
static struct pmc_x86_ops pmc_intel_ops = {
.save_disable_all = pmc_intel_save_disable_all,
.restore_all = pmc_intel_restore_all,
+ .get_status = pmc_intel_get_status,
+ .ack_status = pmc_intel_ack_status,
+ .enable = pmc_intel_enable,
+ .disable = pmc_intel_disable,
.eventsel = MSR_ARCH_PERFMON_EVENTSEL0,
.perfctr = MSR_ARCH_PERFMON_PERFCTR0,
.event_map = pmc_intel_event_map,
+ .raw_event = pmc_intel_raw_event,
.max_events = ARRAY_SIZE(intel_perfmon_event_map),
};

static struct pmc_x86_ops pmc_amd_ops = {
.save_disable_all = pmc_amd_save_disable_all,
.restore_all = pmc_amd_restore_all,
+ .get_status = pmc_amd_get_status,
+ .ack_status = pmc_amd_ack_status,
+ .enable = pmc_amd_enable,
+ .disable = pmc_amd_disable,
.eventsel = MSR_K7_EVNTSEL0,
.perfctr = MSR_K7_PERFCTR0,
.event_map = pmc_amd_event_map,
+ .raw_event = pmc_amd_raw_event,
.max_events = ARRAY_SIZE(amd_perfmon_event_map),
};

@@ -787,8 +954,25 @@ static struct pmc_x86_ops *pmc_intel_ini

static struct pmc_x86_ops *pmc_amd_init(void)
{
+ u64 old;
+ int bits;
+
nr_counters_generic = 4;
nr_counters_fixed = 0;
+ counter_value_mask = ~0ULL;
+
+ rdmsrl(MSR_K7_PERFCTR0, old);
+ wrmsrl(MSR_K7_PERFCTR0, counter_value_mask);
+ /*
+ * read the truncated mask
+ */
+ rdmsrl(MSR_K7_PERFCTR0, counter_value_mask);
+ wrmsrl(MSR_K7_PERFCTR0, old);
+
+ bits = 32 + fls(counter_value_mask >> 32);
+ if (bits == 32)
+ bits = fls((u32)counter_value_mask);
+ counter_value_bits = bits;

pr_info("AMD Performance Monitoring support detected.\n");



2009-03-05 17:26:17

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs


* Peter Zijlstra <[email protected]> wrote:

> Subject: perfcounters: IRQ and NMI support on AMD CPUs
> From: Peter Zijlstra <[email protected]>
> Date: Thu Mar 05 18:08:27 CET 2009
>
> The below completes the K7+ performance counter support.
>
> Signed-off-by: Peter Zijlstra <[email protected]>
> ---
> arch/x86/kernel/cpu/perf_counter.c | 272 +++++++++++++++++++++++++++++++------
> 1 file changed, 228 insertions(+), 44 deletions(-)

Great work, thanks Peter! I've applied it to
tip:perfcounters/core and tip:master.

Ingo

2009-03-05 17:28:24

by Peter Zijlstra

[permalink] [raw]
Subject: [tip:perfcounters/core] perfcounters: IRQ and NMI support on AMD CPUs

Commit-ID: b0f3f28e0f14eb335f67bfaae33ce8b8d74fd58b
Gitweb: http://git.kernel.org/tip/b0f3f28e0f14eb335f67bfaae33ce8b8d74fd58b
Author: "Peter Zijlstra" <[email protected]>
AuthorDate: Thu, 5 Mar 2009 18:08:27 +0100
Commit: Ingo Molnar <[email protected]>
CommitDate: Thu, 5 Mar 2009 18:25:16 +0100

perfcounters: IRQ and NMI support on AMD CPUs

The below completes the K7+ performance counter support:

- IRQ support
- NMI support

KernelTop output works now as well.

Signed-off-by: Peter Zijlstra <[email protected]>
Cc: Jaswinder Singh Rajput <[email protected]>
Cc: Paul Mackerras <[email protected]>
LKML-Reference: <1236273633.5187.286.camel@laptop>
Signed-off-by: Ingo Molnar <[email protected]>


---
arch/x86/kernel/cpu/perf_counter.c | 272 ++++++++++++++++++++++++++++++------
1 files changed, 228 insertions(+), 44 deletions(-)

diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index 3b65f19..6ebe9ab 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -28,6 +28,7 @@ static bool perf_counters_initialized __read_mostly;
static int nr_counters_generic __read_mostly;
static u64 perf_counter_mask __read_mostly;
static u64 counter_value_mask __read_mostly;
+static int counter_value_bits __read_mostly;

static int nr_counters_fixed __read_mostly;

@@ -35,7 +36,9 @@ struct cpu_hw_counters {
struct perf_counter *counters[X86_PMC_IDX_MAX];
unsigned long used[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
unsigned long interrupts;
- u64 global_enable;
+ u64 throttle_ctrl;
+ u64 active_mask;
+ int enabled;
};

/*
@@ -43,21 +46,28 @@ struct cpu_hw_counters {
*/
struct pmc_x86_ops {
u64 (*save_disable_all)(void);
- void (*restore_all)(u64 ctrl);
+ void (*restore_all)(u64);
+ u64 (*get_status)(u64);
+ void (*ack_status)(u64);
+ void (*enable)(int, u64);
+ void (*disable)(int, u64);
unsigned eventsel;
unsigned perfctr;
- int (*event_map)(int event);
+ u64 (*event_map)(int);
+ u64 (*raw_event)(u64);
int max_events;
};

static struct pmc_x86_ops *pmc_ops;

-static DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters);
+static DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters) = {
+ .enabled = 1,
+};

/*
* Intel PerfMon v3. Used on Core2 and later.
*/
-static const int intel_perfmon_event_map[] =
+static const u64 intel_perfmon_event_map[] =
{
[PERF_COUNT_CPU_CYCLES] = 0x003c,
[PERF_COUNT_INSTRUCTIONS] = 0x00c0,
@@ -68,15 +78,29 @@ static const int intel_perfmon_event_map[] =
[PERF_COUNT_BUS_CYCLES] = 0x013c,
};

-static int pmc_intel_event_map(int event)
+static u64 pmc_intel_event_map(int event)
{
return intel_perfmon_event_map[event];
}

+static u64 pmc_intel_raw_event(u64 event)
+{
+#define CORE_EVNTSEL_EVENT_MASK 0x000000FF
+#define CORE_EVNTSEL_UNIT_MASK 0x0000FF00
+#define CORE_EVNTSEL_COUNTER_MASK 0xFF000000
+
+#define CORE_EVNTSEL_MASK \
+ (CORE_EVNTSEL_EVENT_MASK | \
+ CORE_EVNTSEL_UNIT_MASK | \
+ CORE_EVNTSEL_COUNTER_MASK)
+
+ return event & CORE_EVNTSEL_MASK;
+}
+
/*
* AMD Performance Monitor K7 and later.
*/
-static const int amd_perfmon_event_map[] =
+static const u64 amd_perfmon_event_map[] =
{
[PERF_COUNT_CPU_CYCLES] = 0x0076,
[PERF_COUNT_INSTRUCTIONS] = 0x00c0,
@@ -86,11 +110,25 @@ static const int amd_perfmon_event_map[] =
[PERF_COUNT_BRANCH_MISSES] = 0x00c5,
};

-static int pmc_amd_event_map(int event)
+static u64 pmc_amd_event_map(int event)
{
return amd_perfmon_event_map[event];
}

+static u64 pmc_amd_raw_event(u64 event)
+{
+#define K7_EVNTSEL_EVENT_MASK 0x7000000FF
+#define K7_EVNTSEL_UNIT_MASK 0x00000FF00
+#define K7_EVNTSEL_COUNTER_MASK 0x0FF000000
+
+#define K7_EVNTSEL_MASK \
+ (K7_EVNTSEL_EVENT_MASK | \
+ K7_EVNTSEL_UNIT_MASK | \
+ K7_EVNTSEL_COUNTER_MASK)
+
+ return event & K7_EVNTSEL_MASK;
+}
+
/*
* Propagate counter elapsed time into the generic counter.
* Can only be executed on the CPU where the counter is active.
@@ -179,7 +217,7 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
* Raw event type provide the config in the event structure
*/
if (hw_event->raw) {
- hwc->config |= hw_event->type;
+ hwc->config |= pmc_ops->raw_event(hw_event->type);
} else {
if (hw_event->type >= pmc_ops->max_events)
return -EINVAL;
@@ -205,18 +243,24 @@ static u64 pmc_intel_save_disable_all(void)

static u64 pmc_amd_save_disable_all(void)
{
- int idx;
- u64 val, ctrl = 0;
+ struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+ int enabled, idx;
+
+ enabled = cpuc->enabled;
+ cpuc->enabled = 0;
+ barrier();

for (idx = 0; idx < nr_counters_generic; idx++) {
+ u64 val;
+
rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
- if (val & ARCH_PERFMON_EVENTSEL0_ENABLE)
- ctrl |= (1 << idx);
- val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
- wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
+ if (val & ARCH_PERFMON_EVENTSEL0_ENABLE) {
+ val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
+ wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
+ }
}

- return ctrl;
+ return enabled;
}

u64 hw_perf_save_disable(void)
@@ -226,6 +270,9 @@ u64 hw_perf_save_disable(void)

return pmc_ops->save_disable_all();
}
+/*
+ * Exported because of ACPI idle
+ */
EXPORT_SYMBOL_GPL(hw_perf_save_disable);

static void pmc_intel_restore_all(u64 ctrl)
@@ -235,11 +282,18 @@ static void pmc_intel_restore_all(u64 ctrl)

static void pmc_amd_restore_all(u64 ctrl)
{
- u64 val;
+ struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
int idx;

+ cpuc->enabled = ctrl;
+ barrier();
+ if (!ctrl)
+ return;
+
for (idx = 0; idx < nr_counters_generic; idx++) {
- if (ctrl & (1 << idx)) {
+ if (test_bit(idx, (unsigned long *)&cpuc->active_mask)) {
+ u64 val;
+
rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
@@ -254,8 +308,112 @@ void hw_perf_restore(u64 ctrl)

pmc_ops->restore_all(ctrl);
}
+/*
+ * Exported because of ACPI idle
+ */
EXPORT_SYMBOL_GPL(hw_perf_restore);

+static u64 pmc_intel_get_status(u64 mask)
+{
+ u64 status;
+
+ rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
+
+ return status;
+}
+
+static u64 pmc_amd_get_status(u64 mask)
+{
+ u64 status = 0;
+ int idx;
+
+ for (idx = 0; idx < nr_counters_generic; idx++) {
+ s64 val;
+
+ if (!(mask & (1 << idx)))
+ continue;
+
+ rdmsrl(MSR_K7_PERFCTR0 + idx, val);
+ val <<= (64 - counter_value_bits);
+ if (val >= 0)
+ status |= (1 << idx);
+ }
+
+ return status;
+}
+
+static u64 hw_perf_get_status(u64 mask)
+{
+ if (unlikely(!perf_counters_initialized))
+ return 0;
+
+ return pmc_ops->get_status(mask);
+}
+
+static void pmc_intel_ack_status(u64 ack)
+{
+ wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, ack);
+}
+
+static void pmc_amd_ack_status(u64 ack)
+{
+}
+
+static void hw_perf_ack_status(u64 ack)
+{
+ if (unlikely(!perf_counters_initialized))
+ return;
+
+ pmc_ops->ack_status(ack);
+}
+
+static void pmc_intel_enable(int idx, u64 config)
+{
+ wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + idx,
+ config | ARCH_PERFMON_EVENTSEL0_ENABLE);
+}
+
+static void pmc_amd_enable(int idx, u64 config)
+{
+ struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+
+ set_bit(idx, (unsigned long *)&cpuc->active_mask);
+ if (cpuc->enabled)
+ config |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+
+ wrmsrl(MSR_K7_EVNTSEL0 + idx, config);
+}
+
+static void hw_perf_enable(int idx, u64 config)
+{
+ if (unlikely(!perf_counters_initialized))
+ return;
+
+ pmc_ops->enable(idx, config);
+}
+
+static void pmc_intel_disable(int idx, u64 config)
+{
+ wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + idx, config);
+}
+
+static void pmc_amd_disable(int idx, u64 config)
+{
+ struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
+
+ clear_bit(idx, (unsigned long *)&cpuc->active_mask);
+ wrmsrl(MSR_K7_EVNTSEL0 + idx, config);
+
+}
+
+static void hw_perf_disable(int idx, u64 config)
+{
+ if (unlikely(!perf_counters_initialized))
+ return;
+
+ pmc_ops->disable(idx, config);
+}
+
static inline void
__pmc_fixed_disable(struct perf_counter *counter,
struct hw_perf_counter *hwc, unsigned int __idx)
@@ -278,7 +436,7 @@ __pmc_generic_disable(struct perf_counter *counter,
if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL))
__pmc_fixed_disable(counter, hwc, idx);
else
- wrmsr_safe(hwc->config_base + idx, hwc->config, 0);
+ hw_perf_disable(idx, hwc->config);
}

static DEFINE_PER_CPU(u64, prev_left[X86_PMC_IDX_MAX]);
@@ -354,8 +512,7 @@ __pmc_generic_enable(struct perf_counter *counter,
if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL))
__pmc_fixed_enable(counter, hwc, idx);
else
- wrmsr(hwc->config_base + idx,
- hwc->config | ARCH_PERFMON_EVENTSEL0_ENABLE, 0);
+ hw_perf_enable(idx, hwc->config);
}

static int
@@ -567,22 +724,20 @@ perf_handle_group(struct perf_counter *sibling, u64 *status, u64 *overflown)
* This handler is triggered by the local APIC, so the APIC IRQ handling
* rules apply:
*/
-static void __smp_perf_counter_interrupt(struct pt_regs *regs, int nmi)
+static int __smp_perf_counter_interrupt(struct pt_regs *regs, int nmi)
{
int bit, cpu = smp_processor_id();
u64 ack, status;
struct cpu_hw_counters *cpuc = &per_cpu(cpu_hw_counters, cpu);
+ int ret = 0;

- rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, cpuc->global_enable);
-
- /* Disable counters globally */
- wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
- ack_APIC_irq();
+ cpuc->throttle_ctrl = hw_perf_save_disable();

- rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
+ status = hw_perf_get_status(cpuc->throttle_ctrl);
if (!status)
goto out;

+ ret = 1;
again:
inc_irq_stat(apic_perf_irqs);
ack = status;
@@ -618,12 +773,12 @@ again:
}
}

- wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, ack);
+ hw_perf_ack_status(ack);

/*
* Repeat if there is more work to be done:
*/
- rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
+ status = hw_perf_get_status(cpuc->throttle_ctrl);
if (status)
goto again;
out:
@@ -631,32 +786,27 @@ out:
* Restore - do not reenable when global enable is off or throttled:
*/
if (++cpuc->interrupts < PERFMON_MAX_INTERRUPTS)
- wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, cpuc->global_enable);
+ hw_perf_restore(cpuc->throttle_ctrl);
+
+ return ret;
}

void perf_counter_unthrottle(void)
{
struct cpu_hw_counters *cpuc;
- u64 global_enable;

if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
return;

- if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
- return;
-
if (unlikely(!perf_counters_initialized))
return;

- cpuc = &per_cpu(cpu_hw_counters, smp_processor_id());
+ cpuc = &__get_cpu_var(cpu_hw_counters);
if (cpuc->interrupts >= PERFMON_MAX_INTERRUPTS) {
if (printk_ratelimit())
printk(KERN_WARNING "PERFMON: max interrupts exceeded!\n");
- wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, cpuc->global_enable);
+ hw_perf_restore(cpuc->throttle_ctrl);
}
- rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, global_enable);
- if (unlikely(cpuc->global_enable && !global_enable))
- wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, cpuc->global_enable);
cpuc->interrupts = 0;
}

@@ -664,8 +814,8 @@ void smp_perf_counter_interrupt(struct pt_regs *regs)
{
irq_enter();
apic_write(APIC_LVTPC, LOCAL_PERF_VECTOR);
+ ack_APIC_irq();
__smp_perf_counter_interrupt(regs, 0);
-
irq_exit();
}

@@ -722,16 +872,23 @@ perf_counter_nmi_handler(struct notifier_block *self,
{
struct die_args *args = __args;
struct pt_regs *regs;
+ int ret;
+
+ switch (cmd) {
+ case DIE_NMI:
+ case DIE_NMI_IPI:
+ break;

- if (likely(cmd != DIE_NMI_IPI))
+ default:
return NOTIFY_DONE;
+ }

regs = args->regs;

apic_write(APIC_LVTPC, APIC_DM_NMI);
- __smp_perf_counter_interrupt(regs, 1);
+ ret = __smp_perf_counter_interrupt(regs, 1);

- return NOTIFY_STOP;
+ return ret ? NOTIFY_STOP : NOTIFY_OK;
}

static __read_mostly struct notifier_block perf_counter_nmi_notifier = {
@@ -743,18 +900,28 @@ static __read_mostly struct notifier_block perf_counter_nmi_notifier = {
static struct pmc_x86_ops pmc_intel_ops = {
.save_disable_all = pmc_intel_save_disable_all,
.restore_all = pmc_intel_restore_all,
+ .get_status = pmc_intel_get_status,
+ .ack_status = pmc_intel_ack_status,
+ .enable = pmc_intel_enable,
+ .disable = pmc_intel_disable,
.eventsel = MSR_ARCH_PERFMON_EVENTSEL0,
.perfctr = MSR_ARCH_PERFMON_PERFCTR0,
.event_map = pmc_intel_event_map,
+ .raw_event = pmc_intel_raw_event,
.max_events = ARRAY_SIZE(intel_perfmon_event_map),
};

static struct pmc_x86_ops pmc_amd_ops = {
.save_disable_all = pmc_amd_save_disable_all,
.restore_all = pmc_amd_restore_all,
+ .get_status = pmc_amd_get_status,
+ .ack_status = pmc_amd_ack_status,
+ .enable = pmc_amd_enable,
+ .disable = pmc_amd_disable,
.eventsel = MSR_K7_EVNTSEL0,
.perfctr = MSR_K7_PERFCTR0,
.event_map = pmc_amd_event_map,
+ .raw_event = pmc_amd_raw_event,
.max_events = ARRAY_SIZE(amd_perfmon_event_map),
};

@@ -787,8 +954,25 @@ static struct pmc_x86_ops *pmc_intel_init(void)

static struct pmc_x86_ops *pmc_amd_init(void)
{
+ u64 old;
+ int bits;
+
nr_counters_generic = 4;
nr_counters_fixed = 0;
+ counter_value_mask = ~0ULL;
+
+ rdmsrl(MSR_K7_PERFCTR0, old);
+ wrmsrl(MSR_K7_PERFCTR0, counter_value_mask);
+ /*
+ * read the truncated mask
+ */
+ rdmsrl(MSR_K7_PERFCTR0, counter_value_mask);
+ wrmsrl(MSR_K7_PERFCTR0, old);
+
+ bits = 32 + fls(counter_value_mask >> 32);
+ if (bits == 32)
+ bits = fls((u32)counter_value_mask);
+ counter_value_bits = bits;

pr_info("AMD Performance Monitoring support detected.\n");

2009-03-05 18:33:19

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: Re: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs

Hello Peter,

Ahh, so that day you was getting triple fault in this ?

On Thu, 2009-03-05 at 18:20 +0100, Peter Zijlstra wrote:
> Subject: perfcounters: IRQ and NMI support on AMD CPUs
> From: Peter Zijlstra <[email protected]>
> Date: Thu Mar 05 18:08:27 CET 2009
>
> The below completes the K7+ performance counter support.
>
> Signed-off-by: Peter Zijlstra <[email protected]>
> ---
> arch/x86/kernel/cpu/perf_counter.c | 272 +++++++++++++++++++++++++++++++------
> 1 file changed, 228 insertions(+), 44 deletions(-)
>

It was in my TODO list, but I am glad that you finished it :-)

Any how with this patch on my 64 bit AMD box I am getting:

[jaswinder@hpdv5 perfcounters]$ ./perfstat -e 0,1,2,3 ls > /dev/null

Performance counter stats for 'ls':

perfstat: perfstat.c:415: main: Assertion `res == sizeof(single_count)'
failed.
Aborted
[jaswinder@hpdv5 perfcounters]$

[root@hpdv5 perfcounters]# ./kerneltop
KernelTop refresh period: 2 seconds
kerneltop: kerneltop.c:883: main: Assertion `res == sizeof(ip)' failed.
Aborted
[root@hpdv5 perfcounters]#

Thanks,
--
JSR

2009-03-05 18:45:46

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs

On Fri, 2009-03-06 at 00:02 +0530, Jaswinder Singh Rajput wrote:
> Hello Peter,
>
> Ahh, so that day you was getting triple fault in this ?
>
> On Thu, 2009-03-05 at 18:20 +0100, Peter Zijlstra wrote:
> > Subject: perfcounters: IRQ and NMI support on AMD CPUs
> > From: Peter Zijlstra <[email protected]>
> > Date: Thu Mar 05 18:08:27 CET 2009
> >
> > The below completes the K7+ performance counter support.
> >
> > Signed-off-by: Peter Zijlstra <[email protected]>
> > ---
> > arch/x86/kernel/cpu/perf_counter.c | 272 +++++++++++++++++++++++++++++++------
> > 1 file changed, 228 insertions(+), 44 deletions(-)
> >
>
> It was in my TODO list, but I am glad that you finished it :-)
>
> Any how with this patch on my 64 bit AMD box I am getting:
>
> [jaswinder@hpdv5 perfcounters]$ ./perfstat -e 0,1,2,3 ls > /dev/null
>
> Performance counter stats for 'ls':
>
> perfstat: perfstat.c:415: main: Assertion `res == sizeof(single_count)'
> failed.
> Aborted
> [jaswinder@hpdv5 perfcounters]$
>
> [root@hpdv5 perfcounters]# ./kerneltop
> KernelTop refresh period: 2 seconds
> kerneltop: kerneltop.c:883: main: Assertion `res == sizeof(ip)' failed.
> Aborted
> [root@hpdv5 perfcounters]#

Ah, I think you will need a fresh copy of both utilities, Paul recently
changed the ABI.

http://people.redhat.com/mingo/perfcounters/

Contains the latest IIRC

2009-03-05 18:57:24

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: Re: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs

On Thu, 2009-03-05 at 19:45 +0100, Peter Zijlstra wrote:
> On Fri, 2009-03-06 at 00:02 +0530, Jaswinder Singh Rajput wrote:
> >
> > Any how with this patch on my 64 bit AMD box I am getting:
> >
> > [jaswinder@hpdv5 perfcounters]$ ./perfstat -e 0,1,2,3 ls > /dev/null
> >
> > Performance counter stats for 'ls':
> >
> > perfstat: perfstat.c:415: main: Assertion `res == sizeof(single_count)'
> > failed.
> > Aborted
> > [jaswinder@hpdv5 perfcounters]$
> >
> > [root@hpdv5 perfcounters]# ./kerneltop
> > KernelTop refresh period: 2 seconds
> > kerneltop: kerneltop.c:883: main: Assertion `res == sizeof(ip)' failed.
> > Aborted
> > [root@hpdv5 perfcounters]#
>
> Ah, I think you will need a fresh copy of both utilities, Paul recently
> changed the ABI.
>
> http://people.redhat.com/mingo/perfcounters/
>
> Contains the latest IIRC
>

With fresh copy, perfstat is working.

But kerneltop is still not working and I am not getting any NMI Interrupts.

[root@hpdv5 new]# ./kerneltop -e 3 -c 100 -e 2

------------------------------------------------------------------------------
KernelTop: 0 irqs/sec kernel:nan% [NMI, cache-misses/cache-refs], (all, 2 CPUs)
------------------------------------------------------------------------------

weight events RIP kernel function
______ ______ ________________ _______________


--
JSR

2009-03-05 19:08:18

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs

On Fri, 2009-03-06 at 00:26 +0530, Jaswinder Singh Rajput wrote:
> On Thu, 2009-03-05 at 19:45 +0100, Peter Zijlstra wrote:
> > On Fri, 2009-03-06 at 00:02 +0530, Jaswinder Singh Rajput wrote:
> > >
> > > Any how with this patch on my 64 bit AMD box I am getting:
> > >
> > > [jaswinder@hpdv5 perfcounters]$ ./perfstat -e 0,1,2,3 ls > /dev/null
> > >
> > > Performance counter stats for 'ls':
> > >
> > > perfstat: perfstat.c:415: main: Assertion `res == sizeof(single_count)'
> > > failed.
> > > Aborted
> > > [jaswinder@hpdv5 perfcounters]$
> > >
> > > [root@hpdv5 perfcounters]# ./kerneltop
> > > KernelTop refresh period: 2 seconds
> > > kerneltop: kerneltop.c:883: main: Assertion `res == sizeof(ip)' failed.
> > > Aborted
> > > [root@hpdv5 perfcounters]#
> >
> > Ah, I think you will need a fresh copy of both utilities, Paul recently
> > changed the ABI.
> >
> > http://people.redhat.com/mingo/perfcounters/
> >
> > Contains the latest IIRC
> >
>
> With fresh copy, perfstat is working.
>
> But kerneltop is still not working and I am not getting any NMI Interrupts.

What does your dmegs look like?

Mine read like:

[ 0.012002] AMD Performance Monitoring support detected.
[ 0.013002] ... num counters: 4
[ 0.014001] ... value mask: 0000ffffffffffff
[ 0.015001] ... fixed counters: 0
[ 0.016001] ... counter mask: 000000000000000f

and its generating IRQs:

CNT: 168612 166040 Performance counter interrupts

2009-03-05 19:34:44

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs

On Fri, 2009-03-06 at 00:26 +0530, Jaswinder Singh Rajput wrote:

> But kerneltop is still not working and I am not getting any NMI Interrupts.

Does the below work for you?

The BKGD suggests its 48 for all existing machines (it certainly is for
mine).

Index: linux-2.6/arch/x86/kernel/cpu/perf_counter.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/cpu/perf_counter.c
+++ linux-2.6/arch/x86/kernel/cpu/perf_counter.c
@@ -959,20 +959,8 @@ static struct pmc_x86_ops *pmc_amd_init(

nr_counters_generic = 4;
nr_counters_fixed = 0;
- counter_value_mask = ~0ULL;
-
- rdmsrl(MSR_K7_PERFCTR0, old);
- wrmsrl(MSR_K7_PERFCTR0, counter_value_mask);
- /*
- * read the truncated mask
- */
- rdmsrl(MSR_K7_PERFCTR0, counter_value_mask);
- wrmsrl(MSR_K7_PERFCTR0, old);
-
- bits = 32 + fls(counter_value_mask >> 32);
- if (bits == 32)
- bits = fls((u32)counter_value_mask);
- counter_value_bits = bits;
+ counter_value_mask = 0x0000FFFFFFFFFFFFULL;
+ counter_value_bits = 48;

pr_info("AMD Performance Monitoring support detected.\n");


2009-03-05 19:38:18

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: Re: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs

On Thu, 2009-03-05 at 20:07 +0100, Peter Zijlstra wrote:
> On Fri, 2009-03-06 at 00:26 +0530, Jaswinder Singh Rajput wrote:
> >
> > With fresh copy, perfstat is working.
> >
> > But kerneltop is still not working and I am not getting any NMI Interrupts.
>
> What does your dmegs look like?
>
> Mine read like:
>
> [ 0.012002] AMD Performance Monitoring support detected.
> [ 0.013002] ... num counters: 4
> [ 0.014001] ... value mask: 0000ffffffffffff
> [ 0.015001] ... fixed counters: 0
> [ 0.016001] ... counter mask: 000000000000000f
>

[ 0.010998] AMD Performance Monitoring support detected.
[ 0.011006] ... num counters: 4
[ 0.011301] ... value mask: 0000000000000086
[ 0.011581] ... fixed counters: 0
[ 0.011808] ... counter mask: 000000000000000f
[ 0.011998] ACPI: Core revision 20081204

> and its generating IRQs:
>
> CNT: 168612 166040 Performance counter interrupts
>

NMI: 0 0 Non-maskable interrupts
LOC: 213 980394 Local timer interrupts
CNT: 0 0 Performance counter interrupts
RES: 125349 123542 Rescheduling interrupts

--
JSR

2009-03-05 19:41:48

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs


* Peter Zijlstra <[email protected]> wrote:

> On Fri, 2009-03-06 at 00:26 +0530, Jaswinder Singh Rajput wrote:
>
> > But kerneltop is still not working and I am not getting any NMI Interrupts.
>
> Does the below work for you?
>
> The BKGD suggests its 48 for all existing machines (it
> certainly is for mine).

Yeah, this did the trick on AMD/Barcelona!

NMI: 11310 14932 11729 12705 11207
13454 13378 10714 14526 11986 10973
10765 12669 12093 13430 9661 Non-maskable
interrupts

KernelTop works just fine:

------------------------------------------------------------------------------
KernelTop: 1019 irqs/sec kernel:27.9% [NMI, 1000000 CPU
cycles], (all, 16 CPUs)
------------------------------------------------------------------------------

events RIP kernel function
______ ______ ________________ _______________

5260.00 - ffffffff8037e420 : clear_page_c
1065.00 - ffffffff805811a0 : page_fault
699.00 - ffffffff8037e690 : copy_user_generic_string!
669.00 - ffffffff80294ed8 : get_page_from_freelist
575.00 - ffffffff804cd033 : acpi_pm_read
551.00 - ffffffff8025fd1b : generic_exec_single
416.00 - ffffffff80580c9c : _spin_lock
413.00 - ffffffff802a32ad : unmap_vmas
392.00 - ffffffff80580fc2 : _spin_lock_irqsave

Thanks!

Ingo

2009-03-05 20:02:28

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: Re: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs

On Thu, 2009-03-05 at 20:41 +0100, Ingo Molnar wrote:
> * Peter Zijlstra <[email protected]> wrote:
>
> > On Fri, 2009-03-06 at 00:26 +0530, Jaswinder Singh Rajput wrote:
> >
> > > But kerneltop is still not working and I am not getting any NMI Interrupts.
> >
> > Does the below work for you?
> >
> > The BKGD suggests its 48 for all existing machines (it
> > certainly is for mine).
>
> Yeah, this did the trick on AMD/Barcelona!
>

Nice.

but on my AMD box I got interrupts and NMI for some time:

NMI: 100 1108209 Non-maskable interrupts
LOC: 213 192815 Local timer interrupts
CNT: 100 1108206 Performance counter interrupts
RES: 21132 20397 Rescheduling interrupts

but kerneltop does not show anything, it only shows # irqs/sec for some
time and then irqs also become 0.

Here is demg:

kerneltop
[ 196.677297] Uhhuh. NMI received for unknown reason 00 on CPU 1.
[ 196.677297] Do you have a strange power saving mode enabled?
[ 196.677297] Dazed and confused, but trying to continue
[ 198.854293] PERFMON: max interrupts exceeded!
[ 198.865302] PERFMON: max interrupts exceeded!
[ 198.866304] PERFMON: max interrupts exceeded!
[ 206.066271] PERFMON: max interrupts exceeded!
[ 206.067304] PERFMON: max interrupts exceeded!
[ 206.068265] PERFMON: max interrupts exceeded!
[ 211.176291] PERFMON: max interrupts exceeded!
[ 211.177302] PERFMON: max interrupts exceeded!
[ 211.235304] PERFMON: max interrupts exceeded!
[ 211.236296] PERFMON: max interrupts exceeded!
[ 214.245302] PERFMON: max interrupts exceeded!
[ 225.257276] PERFMON: max interrupts exceeded!
[ 225.258271] PERFMON: max interrupts exceeded!
[ 297.385301] PERFMON: max interrupts exceeded!
[ 297.386290] PERFMON: max interrupts exceeded!
[ 310.405304] PERFMON: max interrupts exceeded!
[ 392.677261] Uhhuh. NMI received for unknown reason 00 on CPU 1.
[ 392.677261] Do you have a strange power saving mode enabled?
[ 392.677261] Dazed and confused, but trying to continue
[ 394.837275] PERFMON: max interrupts exceeded!
[ 394.848268] PERFMON: max interrupts exceeded!
[ 394.849266] PERFMON: max interrupts exceeded!
[ 396.891309] PERFMON: max interrupts exceeded!
[ 396.892294] PERFMON: max interrupts exceeded!
[ 397.415302] PERFMON: max interrupts exceeded!
[ 397.594299] PERFMON: max interrupts exceeded!
[ 398.395302] PERFMON: max interrupts exceeded!
[ 398.919304] PERFMON: max interrupts exceeded!
[ 403.839309] __ratelimit: 1 callbacks suppressed
[ 403.839319] PERFMON: max interrupts exceeded!
[ 403.840302] PERFMON: max interrupts exceeded!
[ 403.841298] PERFMON: max interrupts exceeded!
[ 403.842297] PERFMON: max interrupts exceeded!
[ 403.843267] PERFMON: max interrupts exceeded!
[ 403.853303] PERFMON: max interrupts exceeded!
[ 403.854290] PERFMON: max interrupts exceeded!
[ 403.855301] PERFMON: max interrupts exceeded!
[ 403.857301] PERFMON: max interrupts exceeded!
[ 403.858304] PERFMON: max interrupts exceeded!
[ 409.097310] __ratelimit: 13 callbacks suppressed
[ 409.097321] PERFMON: max interrupts exceeded!
[ 409.098299] PERFMON: max interrupts exceeded!
[ 411.138303] PERFMON: max interrupts exceeded!
[ 413.177301] PERFMON: max interrupts exceeded!
[ 413.178289] PERFMON: max interrupts exceeded!
[ 414.442311] PERFMON: max interrupts exceeded!
[ 415.217304] PERFMON: max interrupts exceeded!
[ 415.218291] PERFMON: max interrupts exceeded!
[ 417.257307] PERFMON: max interrupts exceeded!
[ 417.258294] PERFMON: max interrupts exceeded!
[ 418.585295] PERFMON: max interrupts exceeded!
[ 418.600293] PERFMON: max interrupts exceeded!
[ 427.436301] PERFMON: max interrupts exceeded!
[ 427.437307] PERFMON: max interrupts exceeded!
[ 429.477269] PERFMON: max interrupts exceeded!
[ 429.479264] PERFMON: max interrupts exceeded!
[ 431.514269] PERFMON: max interrupts exceeded!
[ 431.516294] PERFMON: max interrupts exceeded!
[ 433.557303] PERFMON: max interrupts exceeded!
[ 433.558290] PERFMON: max interrupts exceeded!
[ 435.585305] PERFMON: max interrupts exceeded!
[ 435.586291] PERFMON: max interrupts exceeded!
[ 435.620276] PERFMON: max interrupts exceeded!
[ 437.619294] PERFMON: max interrupts exceeded!
[ 437.620295] PERFMON: max interrupts exceeded!
[ 437.621289] PERFMON: max interrupts exceeded!
[ 437.622290] PERFMON: max interrupts exceeded!
[ 439.637302] PERFMON: max interrupts exceeded!
[ 439.638291] PERFMON: max interrupts exceeded!
[ 439.645301] PERFMON: max interrupts exceeded!
[ 439.646298] PERFMON: max interrupts exceeded!
[ 441.684302] PERFMON: max interrupts exceeded!
[ 441.685298] PERFMON: max interrupts exceeded!
[ 456.974308] PERFMON: max interrupts exceeded!
[ 466.542303] PERFMON: max interrupts exceeded!
[ 468.924294] PERFMON: max interrupts exceeded!
[ 471.246282] PERFMON: max interrupts exceeded!
[ 471.257269] PERFMON: max interrupts exceeded!
[ 471.258268] PERFMON: max interrupts exceeded!
[ 473.295297] PERFMON: max interrupts exceeded!
[ 473.296301] PERFMON: max interrupts exceeded!
[ 475.312292] PERFMON: max interrupts exceeded!
[ 475.323302] PERFMON: max interrupts exceeded!
[ 475.324302] PERFMON: max interrupts exceeded!
[ 477.346303] PERFMON: max interrupts exceeded!
[ 477.347300] PERFMON: max interrupts exceeded!
[ 479.381303] PERFMON: max interrupts exceeded!
[ 480.685269] PERFMON: max interrupts exceeded!
[ 480.686270] PERFMON: max interrupts exceeded!
[ 481.405307] PERFMON: max interrupts exceeded!
[ 483.425304] PERFMON: max interrupts exceeded!
[ 483.426291] PERFMON: max interrupts exceeded!
[ 485.461306] PERFMON: max interrupts exceeded!
[ 485.462293] PERFMON: max interrupts exceeded!
[ 487.499304] PERFMON: max interrupts exceeded!
[ 487.500290] PERFMON: max interrupts exceeded!
[ 489.524279] PERFMON: max interrupts exceeded!
[ 491.546304] PERFMON: max interrupts exceeded!
[ 491.547292] PERFMON: max interrupts exceeded!
[ 491.548285] PERFMON: max interrupts exceeded!
[ 493.581307] PERFMON: max interrupts exceeded!
[ 493.582301] PERFMON: max interrupts exceeded!
[ 495.605303] PERFMON: max interrupts exceeded!
[ 495.606311] PERFMON: max interrupts exceeded!
[ 497.641303] PERFMON: max interrupts exceeded!
[ 499.665303] PERFMON: max interrupts exceeded!
[ 499.666325] PERFMON: max interrupts exceeded!
[ 501.699295] PERFMON: max interrupts exceeded!
[ 501.700301] PERFMON: max interrupts exceeded!
[ 503.715304] PERFMON: max interrupts exceeded!
[ 503.716292] PERFMON: max interrupts exceeded!
[ 503.717309] PERFMON: max interrupts exceeded!
[ 503.725302] PERFMON: max interrupts exceeded!
[ 505.748271] PERFMON: max interrupts exceeded!
[ 505.749382] PERFMON: max interrupts exceeded!
[ 507.782304] PERFMON: max interrupts exceeded!
[ 507.783291] PERFMON: max interrupts exceeded!
[ 509.804303] PERFMON: max interrupts exceeded!
[ 509.805302] PERFMON: max interrupts exceeded!
[ 511.840303] PERFMON: max interrupts exceeded!
[ 511.841299] PERFMON: max interrupts exceeded!
[ 515.565261] Uhhuh. NMI received for unknown reason 00 on CPU 1.
[ 515.565261] Do you have a strange power saving mode enabled?
[ 515.565261] Dazed and confused, but trying to continue
[ 515.569284] PERFMON: max interrupts exceeded!
[ 515.570372] PERFMON: max interrupts exceeded!
[ 515.571355] PERFMON: max interrupts exceeded!
[ 515.574304] PERFMON: max interrupts exceeded!
[ 515.575287] PERFMON: max interrupts exceeded!
[ 515.576283] PERFMON: max interrupts exceeded!
[ 515.577289] PERFMON: max interrupts exceeded!
[ 515.579318] PERFMON: max interrupts exceeded!
[ 516.948088] __ratelimit: 113 callbacks suppressed
[ 516.948118] PERFMON: max interrupts exceeded!
[ 516.951315] PERFMON: max interrupts exceeded!
[ 516.952298] PERFMON: max interrupts exceeded!
[ 516.953315] PERFMON: max interrupts exceeded!
[ 516.954406] PERFMON: max interrupts exceeded!
[ 516.955390] PERFMON: max interrupts exceeded!
[ 516.956336] PERFMON: max interrupts exceeded!
[ 516.957277] PERFMON: max interrupts exceeded!
[ 516.958285] PERFMON: max interrupts exceeded!
[ 516.959313] PERFMON: max interrupts exceeded!
[ 522.039265] __ratelimit: 248 callbacks suppressed
[ 522.039294] PERFMON: max interrupts exceeded!
[ 522.040321] PERFMON: max interrupts exceeded!
[ 522.042299] PERFMON: max interrupts exceeded!
[ 522.043287] PERFMON: max interrupts exceeded!
[ 522.044277] PERFMON: max interrupts exceeded!
[ 522.045299] PERFMON: max interrupts exceeded!
[ 522.048017] PERFMON: max interrupts exceeded!
[ 522.148095] PERFMON: max interrupts exceeded!
[ 522.149279] PERFMON: max interrupts exceeded!
[ 522.151350] PERFMON: max interrupts exceeded!
[ 527.043304] __ratelimit: 1024 callbacks suppressed
[ 527.043314] PERFMON: max interrupts exceeded!
[ 527.044303] PERFMON: max interrupts exceeded!
[ 527.045298] PERFMON: max interrupts exceeded!
[ 527.046291] PERFMON: max interrupts exceeded!
[ 527.047271] PERFMON: max interrupts exceeded!
[ 527.048276] PERFMON: max interrupts exceeded!
[ 527.049303] PERFMON: max interrupts exceeded!
[ 527.052303] PERFMON: max interrupts exceeded!
[ 527.053566] PERFMON: max interrupts exceeded!
[ 527.054304] PERFMON: max interrupts exceeded!
[ 532.049312] __ratelimit: 2191 callbacks suppressed
[ 532.049321] PERFMON: max interrupts exceeded!
[ 532.050303] PERFMON: max interrupts exceeded!
[ 532.052298] PERFMON: max interrupts exceeded!
[ 532.053305] PERFMON: max interrupts exceeded!
[ 532.065291] PERFMON: max interrupts exceeded!
[ 532.067263] PERFMON: max interrupts exceeded!
[ 532.069299] PERFMON: max interrupts exceeded!
[ 532.071300] PERFMON: max interrupts exceeded!
[ 532.073311] PERFMON: max interrupts exceeded!
[ 532.075302] PERFMON: max interrupts exceeded!
[ 537.062306] __ratelimit: 1414 callbacks suppressed
[ 537.062335] PERFMON: max interrupts exceeded!
[ 537.063443] PERFMON: max interrupts exceeded!
[ 537.066285] PERFMON: max interrupts exceeded!
[ 537.067289] PERFMON: max interrupts exceeded!
[ 537.068282] PERFMON: max interrupts exceeded!
[ 537.069322] PERFMON: max interrupts exceeded!
[ 537.071312] PERFMON: max interrupts exceeded!
[ 537.072295] PERFMON: max interrupts exceeded!
[ 537.073279] PERFMON: max interrupts exceeded!
[ 537.074287] PERFMON: max interrupts exceeded!
[root@hpdv5 new]#

--
JSR

2009-03-06 06:38:19

by Mike Galbraith

[permalink] [raw]
Subject: Re: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs

On Fri, 2009-03-06 at 01:31 +0530, Jaswinder Singh Rajput wrote:
> On Thu, 2009-03-05 at 20:41 +0100, Ingo Molnar wrote:
> > * Peter Zijlstra <[email protected]> wrote:
> >
> > > On Fri, 2009-03-06 at 00:26 +0530, Jaswinder Singh Rajput wrote:
> > >
> > > > But kerneltop is still not working and I am not getting any NMI Interrupts.
> > >
> > > Does the below work for you?
> > >
> > > The BKGD suggests its 48 for all existing machines (it
> > > certainly is for mine).
> >
> > Yeah, this did the trick on AMD/Barcelona!
> >
>
> Nice.
>
> but on my AMD box I got interrupts and NMI for some time:
>
> NMI: 100 1108209 Non-maskable interrupts
> LOC: 213 192815 Local timer interrupts
> CNT: 100 1108206 Performance counter interrupts
> RES: 21132 20397 Rescheduling interrupts
>
> but kerneltop does not show anything, it only shows # irqs/sec for some
> time and then irqs also become 0.

Hm. Kerneltop on my Q6600 has ceased to function with n 1 as well, but
n 0 still works. Zero NMIs.

Perfstat has also gone south.
perfstat: perfstat.c:423: main: Assertion `res == sizeof(single_count)' failed.

-Mike

2009-03-06 06:51:56

by Mike Galbraith

[permalink] [raw]
Subject: Re: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs

On Fri, 2009-03-06 at 07:37 +0100, Mike Galbraith wrote:
> On Fri, 2009-03-06 at 01:31 +0530, Jaswinder Singh Rajput wrote:
> > On Thu, 2009-03-05 at 20:41 +0100, Ingo Molnar wrote:
> > > * Peter Zijlstra <[email protected]> wrote:
> > >
> > > > On Fri, 2009-03-06 at 00:26 +0530, Jaswinder Singh Rajput wrote:
> > > >
> > > > > But kerneltop is still not working and I am not getting any NMI Interrupts.
> > > >
> > > > Does the below work for you?
> > > >
> > > > The BKGD suggests its 48 for all existing machines (it
> > > > certainly is for mine).
> > >
> > > Yeah, this did the trick on AMD/Barcelona!
> > >
> >
> > Nice.
> >
> > but on my AMD box I got interrupts and NMI for some time:
> >
> > NMI: 100 1108209 Non-maskable interrupts
> > LOC: 213 192815 Local timer interrupts
> > CNT: 100 1108206 Performance counter interrupts
> > RES: 21132 20397 Rescheduling interrupts
> >
> > but kerneltop does not show anything, it only shows # irqs/sec for some
> > time and then irqs also become 0.
>
> Hm. Kerneltop on my Q6600 has ceased to function with n 1 as well, but
> n 0 still works. Zero NMIs.
>
> Perfstat has also gone south.
> perfstat: perfstat.c:423: main: Assertion `res == sizeof(single_count)' failed.

Ah, my woes are gonna be 2743a5b0fa6f309da904f2190a9cc25deee34dbd.

Never mind.

-Mike

2009-03-06 07:12:17

by Mike Galbraith

[permalink] [raw]
Subject: Re: [PATCH] perfcounters: IRQ and NMI support on AMD CPUs

On Fri, 2009-03-06 at 07:51 +0100, Mike Galbraith wrote:

> Ah, my woes are gonna be 2743a5b0fa6f309da904f2190a9cc25deee34dbd.

(and indeed, they both work fine now)

Subject: Re: [tip:perfcounters/core] perfcounters: IRQ and NMI support on AMD CPUs

On 05.03.09 17:27:29, Peter Zijlstra wrote:
> Commit-ID: b0f3f28e0f14eb335f67bfaae33ce8b8d74fd58b
> Gitweb: http://git.kernel.org/tip/b0f3f28e0f14eb335f67bfaae33ce8b8d74fd58b
> Author: "Peter Zijlstra" <[email protected]>
> AuthorDate: Thu, 5 Mar 2009 18:08:27 +0100
> Commit: Ingo Molnar <[email protected]>
> CommitDate: Thu, 5 Mar 2009 18:25:16 +0100
>
> perfcounters: IRQ and NMI support on AMD CPUs
>
> The below completes the K7+ performance counter support:
>
> - IRQ support
> - NMI support
>
> KernelTop output works now as well.
>
> Signed-off-by: Peter Zijlstra <[email protected]>
> Cc: Jaswinder Singh Rajput <[email protected]>
> Cc: Paul Mackerras <[email protected]>
> LKML-Reference: <1236273633.5187.286.camel@laptop>
> Signed-off-by: Ingo Molnar <[email protected]>
>
>
> ---
> arch/x86/kernel/cpu/perf_counter.c | 272 ++++++++++++++++++++++++++++++------
> 1 files changed, 228 insertions(+), 44 deletions(-)
>
> diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
> index 3b65f19..6ebe9ab 100644
> --- a/arch/x86/kernel/cpu/perf_counter.c
> +++ b/arch/x86/kernel/cpu/perf_counter.c

[...]

> @@ -205,18 +243,24 @@ static u64 pmc_intel_save_disable_all(void)
>
> static u64 pmc_amd_save_disable_all(void)
> {
> - int idx;
> - u64 val, ctrl = 0;
> + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
> + int enabled, idx;
> +
> + enabled = cpuc->enabled;
> + cpuc->enabled = 0;
> + barrier();

Peter,

please add comments to all barrier()s you added to this file. Is it
sufficient in hw_perf_save_disable() to stop NMI's only on the current
core?

-Robert

>
> for (idx = 0; idx < nr_counters_generic; idx++) {
> + u64 val;
> +
> rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
> - if (val & ARCH_PERFMON_EVENTSEL0_ENABLE)
> - ctrl |= (1 << idx);
> - val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
> - wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
> + if (val & ARCH_PERFMON_EVENTSEL0_ENABLE) {
> + val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
> + wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
> + }
> }
>
> - return ctrl;
> + return enabled;
> }
>
> u64 hw_perf_save_disable(void)

[...]

--
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]

2009-03-12 09:12:37

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [tip:perfcounters/core] perfcounters: IRQ and NMI support on AMD CPUs

On Thu, 2009-03-12 at 02:44 +0100, Robert Richter wrote:
> On 05.03.09 17:27:29, Peter Zijlstra wrote:
> > Commit-ID: b0f3f28e0f14eb335f67bfaae33ce8b8d74fd58b
> > Gitweb: http://git.kernel.org/tip/b0f3f28e0f14eb335f67bfaae33ce8b8d74fd58b
> > Author: "Peter Zijlstra" <[email protected]>
> > AuthorDate: Thu, 5 Mar 2009 18:08:27 +0100
> > Commit: Ingo Molnar <[email protected]>
> > CommitDate: Thu, 5 Mar 2009 18:25:16 +0100
> >
> > perfcounters: IRQ and NMI support on AMD CPUs
> >
> > The below completes the K7+ performance counter support:
> >
> > - IRQ support
> > - NMI support
> >
> > KernelTop output works now as well.
> >
> > Signed-off-by: Peter Zijlstra <[email protected]>
> > Cc: Jaswinder Singh Rajput <[email protected]>
> > Cc: Paul Mackerras <[email protected]>
> > LKML-Reference: <1236273633.5187.286.camel@laptop>
> > Signed-off-by: Ingo Molnar <[email protected]>
> >
> >
> > ---
> > arch/x86/kernel/cpu/perf_counter.c | 272 ++++++++++++++++++++++++++++++------
> > 1 files changed, 228 insertions(+), 44 deletions(-)
> >
> > diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
> > index 3b65f19..6ebe9ab 100644
> > --- a/arch/x86/kernel/cpu/perf_counter.c
> > +++ b/arch/x86/kernel/cpu/perf_counter.c
>
> [...]
>
> > @@ -205,18 +243,24 @@ static u64 pmc_intel_save_disable_all(void)
> >
> > static u64 pmc_amd_save_disable_all(void)
> > {
> > - int idx;
> > - u64 val, ctrl = 0;
> > + struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
> > + int enabled, idx;
> > +
> > + enabled = cpuc->enabled;
> > + cpuc->enabled = 0;
> > + barrier();
>
> Peter,
>
> please add comments to all barrier()s you added to this file. Is it
> sufficient in hw_perf_save_disable() to stop NMI's only on the current
> core?

Yes, counters are fundamentally per cpu. But you're right, I'll go
through the code and add comments and fix up some barriers.