powerpc/perf: Sample only if SIAR-Valid bit is set in P7+
authorsukadev@linux.vnet.ibm.com <sukadev@linux.vnet.ibm.com>
Tue, 18 Sep 2012 20:56:11 +0000 (20:56 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 27 Sep 2012 02:51:05 +0000 (12:51 +1000)
powerpc/perf: Sample only if SIAR-Valid bit is set in P7+

On POWER7+ two new bits (mmcra[35] and mmcra[36]) indicate whether the
contents of SIAR and SDAR are valid.

For marked instructions on P7+, we must save the contents of SIAR and
SDAR registers only if these new bits are set.

This code/check for the SIAR-Valid bit is specific to P7+, so rather than
waste a CPU-feature bit use the PVR flag.

Note that Carl Love proposed a similar change for oprofile:

        https://lkml.org/lkml/2012/6/22/309

Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/perf_event_server.h
arch/powerpc/include/asm/reg.h
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/power7-pmu.c

index 078019b5b353c916f49dd0d71087260302569c60..9710be3a2d1753e7fef95287d182811e5ce5a0ba 100644 (file)
@@ -49,6 +49,7 @@ struct power_pmu {
 #define PPMU_ALT_SIPR          2       /* uses alternate posn for SIPR/HV */
 #define PPMU_NO_SIPR           4       /* no SIPR/HV in MMCRA at all */
 #define PPMU_NO_CONT_SAMPLING  8       /* no continuous sampling */
+#define PPMU_SIAR_VALID                16      /* Processor has SIAR Valid bit */
 
 /*
  * Values for flags to get_alternatives()
index a1096fb6281673edef18701ef3d9c6e972f8a170..d24c14163966599ed3a78f559f80191f7cd53693 100644 (file)
 #define   POWER6_MMCRA_SIPR   0x0000020000000000ULL
 #define   POWER6_MMCRA_THRM    0x00000020UL
 #define   POWER6_MMCRA_OTHER   0x0000000EUL
+
+#define   POWER7P_MMCRA_SIAR_VALID 0x10000000  /* P7+ SIAR contents valid */
+#define   POWER7P_MMCRA_SDAR_VALID 0x08000000  /* P7+ SDAR contents valid */
+
 #define SPRN_PMC1      787
 #define SPRN_PMC2      788
 #define SPRN_PMC3      789
index fb55da91aa45028f796170cf63ece7239d9d89b1..0db88f501f91c953c86dcbef4ab2d768be126f9d 100644 (file)
@@ -82,6 +82,11 @@ static inline int perf_intr_is_nmi(struct pt_regs *regs)
        return 0;
 }
 
+static inline int siar_valid(struct pt_regs *regs)
+{
+       return 1;
+}
+
 #endif /* CONFIG_PPC32 */
 
 /*
@@ -106,14 +111,20 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
  * If we're not doing instruction sampling, give them the SDAR
  * (sampled data address).  If we are doing instruction sampling, then
  * only give them the SDAR if it corresponds to the instruction
- * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC
- * bit in MMCRA.
+ * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC or
+ * the [POWER7P_]MMCRA_SDAR_VALID bit in MMCRA.
  */
 static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
 {
        unsigned long mmcra = regs->dsisr;
-       unsigned long sdsync = (ppmu->flags & PPMU_ALT_SIPR) ?
-               POWER6_MMCRA_SDSYNC : MMCRA_SDSYNC;
+       unsigned long sdsync;
+
+       if (ppmu->flags & PPMU_SIAR_VALID)
+               sdsync = POWER7P_MMCRA_SDAR_VALID;
+       else if (ppmu->flags & PPMU_ALT_SIPR)
+               sdsync = POWER6_MMCRA_SDSYNC;
+       else
+               sdsync = MMCRA_SDSYNC;
 
        if (!(mmcra & MMCRA_SAMPLE_ENABLE) || (mmcra & sdsync))
                *addrp = mfspr(SPRN_SDAR);
@@ -230,6 +241,24 @@ static inline int perf_intr_is_nmi(struct pt_regs *regs)
        return !regs->softe;
 }
 
+/*
+ * On processors like P7+ that have the SIAR-Valid bit, marked instructions
+ * must be sampled only if the SIAR-valid bit is set.
+ *
+ * For unmarked instructions and for processors that don't have the SIAR-Valid
+ * bit, assume that SIAR is valid.
+ */
+static inline int siar_valid(struct pt_regs *regs)
+{
+       unsigned long mmcra = regs->dsisr;
+       int marked = mmcra & MMCRA_SAMPLE_ENABLE;
+
+       if ((ppmu->flags & PPMU_SIAR_VALID) && marked)
+               return mmcra & POWER7P_MMCRA_SIAR_VALID;
+
+       return 1;
+}
+
 #endif /* CONFIG_PPC64 */
 
 static void perf_event_interrupt(struct pt_regs *regs);
@@ -1291,6 +1320,7 @@ struct pmu power_pmu = {
        .event_idx      = power_pmu_event_idx,
 };
 
+
 /*
  * A counter has overflowed; update its count and record
  * things if requested.  Note that interrupts are hard-disabled
@@ -1324,7 +1354,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
                        left += period;
                        if (left <= 0)
                                left = period;
-                       record = 1;
+                       record = siar_valid(regs);
                        event->hw.last_period = event->hw.sample_period;
                }
                if (left < 0x80000000LL)
@@ -1374,8 +1404,10 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs)
 {
        unsigned long use_siar = regs->result;
 
-       if (use_siar)
+       if (use_siar && siar_valid(regs))
                return mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
+       else if (use_siar)
+               return 0;               // no valid instruction pointer
        else
                return regs->nip;
 }
index 1251e4d7e2627b891475cea5231c5f977ef819e7..441af08edf434cc9729d0df344e422f32f487962 100644 (file)
@@ -373,6 +373,9 @@ static int __init init_power7_pmu(void)
            strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7"))
                return -ENODEV;
 
+       if (pvr_version_is(PVR_POWER7p))
+               power7_pmu.flags |= PPMU_SIAR_VALID;
+
        return register_power_pmu(&power7_pmu);
 }