Re: [patch] perf_counter: Add p6 PMU

From: Peter Zijlstra
Date: Thu Jul 09 2009 - 09:25:08 EST


On Thu, 2009-07-09 at 00:14 +0200, Peter Zijlstra wrote:
> On Wed, 2009-07-08 at 23:45 +0200, Peter Zijlstra wrote:
> > On Wed, 2009-07-08 at 17:46 -0400, Vince Weaver wrote:
> > > On Wed, 8 Jul 2009, Peter Zijlstra wrote:
> > >
> > > > doesn't sound like the right kind of event.. but then, it doesn't
> > > > have anything better either.
> > >
> > > Is there a way to specify "invalid event"? Just setting it to 0 doesn't
> > > work, on the Pentium Pro event 0 returns what looks like essentially
> > > random numbers.
> >
> > Hmm, bugger. I was assuming writing 0 to the evensel would disable the
> > counter. Apparently that only works for eventsel1, which would mean we
> > cannot run counter1 without counter0. That means we'd need to do a
> > counter swap at times... :/
>
> Ooh, we can instead use a counter that's specified to not count anything
> for 'disabling' the counter, like event 0x2E with unit mask 0.

The below seems to work..

---
arch/x86/kernel/cpu/perf_counter.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 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
@@ -84,6 +84,14 @@ static u64 p6_pmu_event_map(int event)
return p6_perfmon_event_map[event];
}

+/*
+ * Counter setting that is specified not to count anything.
+ * We use this to effectively disable a counter.
+ *
+ * L2_RQSTS with 0 MESI unit mask.
+ */
+#define P6_NOP_COUNTER 0x0000002EULL
+
static u64 p6_pmu_raw_event(u64 event)
{
#define P6_EVNTSEL_EVENT_MASK 0x000000FFULL
@@ -704,6 +712,7 @@ static int __hw_perf_counter_init(struct
{
struct perf_counter_attr *attr = &counter->attr;
struct hw_perf_counter *hwc = &counter->hw;
+ u64 config;
int err;

if (!x86_pmu_initialized())
@@ -756,10 +765,19 @@ static int __hw_perf_counter_init(struct

if (attr->config >= x86_pmu.max_events)
return -EINVAL;
+
/*
* The generic map:
*/
- hwc->config |= x86_pmu.event_map(attr->config);
+ config = x86_pmu.event_map(attr->config);
+
+ if (config == 0)
+ return -ENOENT;
+
+ if (config == -1LL)
+ return -EINVAL;
+
+ hwc->config |= config;

return 0;
}
@@ -767,7 +785,7 @@ static int __hw_perf_counter_init(struct
static void p6_pmu_disable_all(void)
{
struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
- unsigned long val;
+ u64 val;

if (!cpuc->enabled)
return;
@@ -917,10 +935,10 @@ static inline void
p6_pmu_disable_counter(struct hw_perf_counter *hwc, int idx)
{
struct cpu_hw_counters *cpuc = &__get_cpu_var(cpu_hw_counters);
- unsigned long val = ARCH_PERFMON_EVENTSEL0_ENABLE;
+ u64 val = P6_NOP_COUNTER;

- if (!cpuc->enabled)
- val = 0;
+ if (cpuc->enabled)
+ val |= ARCH_PERFMON_EVENTSEL0_ENABLE;

(void)checking_wrmsrl(hwc->config_base + idx, val);
}

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/