powerpc/perf: Export memory hierarchy info to user space
authorMadhavan Srinivasan <maddy@linux.vnet.ibm.com>
Tue, 11 Apr 2017 01:51:06 +0000 (07:21 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Wed, 19 Apr 2017 10:00:21 +0000 (20:00 +1000)
The LDST field and DATA_SRC in SIER identifies the memory hierarchy level
(eg: L1, L2 etc), from which a data-cache miss for a marked instruction
was satisfied. Use the 'perf_mem_data_src' object to export this
hierarchy level to user space.

Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/perf_event_server.h
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/isa207-common.c
arch/powerpc/perf/isa207-common.h

index ae0a23091a9b347d3e31ed96330772bc9caa3020..446cdcd9b7f5dd24e3683dec94fb0082792cbcf6 100644 (file)
@@ -38,6 +38,8 @@ struct power_pmu {
                                unsigned long *valp);
        int             (*get_alternatives)(u64 event_id, unsigned int flags,
                                u64 alt[]);
+       void            (*get_mem_data_src)(union perf_mem_data_src *dsrc,
+                               u32 flags, struct pt_regs *regs);
        u64             (*bhrb_filter_map)(u64 branch_sample_type);
        void            (*config_bhrb)(u64 pmu_bhrb_filter);
        void            (*disable_pmc)(unsigned int pmc, unsigned long mmcr[]);
index 2ff13249f87a61759f015d7fff93bd014dba6347..e241ebebab6f8628d6ca2aa0d90d88055922dd49 100644 (file)
@@ -2049,6 +2049,10 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
                        data.br_stack = &cpuhw->bhrb_stack;
                }
 
+               if (event->attr.sample_type & PERF_SAMPLE_DATA_SRC &&
+                                               ppmu->get_mem_data_src)
+                       ppmu->get_mem_data_src(&data.data_src, ppmu->flags, regs);
+
                if (perf_event_overflow(event, &data, regs))
                        power_pmu_stop(event, 0);
        }
index cd951fd231c4040ba653f32cf485eebb22d1d805..a8b100ef8e6c2bfb476157fccb9dd3a627d0b782 100644 (file)
@@ -148,6 +148,80 @@ static bool is_thresh_cmp_valid(u64 event)
        return true;
 }
 
+static inline u64 isa207_find_source(u64 idx, u32 sub_idx)
+{
+       u64 ret = PERF_MEM_NA;
+
+       switch(idx) {
+       case 0:
+               /* Nothing to do */
+               break;
+       case 1:
+               ret = PH(LVL, L1);
+               break;
+       case 2:
+               ret = PH(LVL, L2);
+               break;
+       case 3:
+               ret = PH(LVL, L3);
+               break;
+       case 4:
+               if (sub_idx <= 1)
+                       ret = PH(LVL, LOC_RAM);
+               else if (sub_idx > 1 && sub_idx <= 2)
+                       ret = PH(LVL, REM_RAM1);
+               else
+                       ret = PH(LVL, REM_RAM2);
+               ret |= P(SNOOP, HIT);
+               break;
+       case 5:
+               ret = PH(LVL, REM_CCE1);
+               if ((sub_idx == 0) || (sub_idx == 2) || (sub_idx == 4))
+                       ret |= P(SNOOP, HIT);
+               else if ((sub_idx == 1) || (sub_idx == 3) || (sub_idx == 5))
+                       ret |= P(SNOOP, HITM);
+               break;
+       case 6:
+               ret = PH(LVL, REM_CCE2);
+               if ((sub_idx == 0) || (sub_idx == 2))
+                       ret |= P(SNOOP, HIT);
+               else if ((sub_idx == 1) || (sub_idx == 3))
+                       ret |= P(SNOOP, HITM);
+               break;
+       case 7:
+               ret = PM(LVL, L1);
+               break;
+       }
+
+       return ret;
+}
+
+void isa207_get_mem_data_src(union perf_mem_data_src *dsrc, u32 flags,
+                                                       struct pt_regs *regs)
+{
+       u64 idx;
+       u32 sub_idx;
+       u64 sier;
+       u64 val;
+
+       /* Skip if no SIER support */
+       if (!(flags & PPMU_HAS_SIER)) {
+               dsrc->val = 0;
+               return;
+       }
+
+       sier = mfspr(SPRN_SIER);
+       val = (sier & ISA207_SIER_TYPE_MASK) >> ISA207_SIER_TYPE_SHIFT;
+       if (val == 1 || val == 2) {
+               idx = (sier & ISA207_SIER_LDST_MASK) >> ISA207_SIER_LDST_SHIFT;
+               sub_idx = (sier & ISA207_SIER_DATA_SRC_MASK) >> ISA207_SIER_DATA_SRC_SHIFT;
+
+               dsrc->val = isa207_find_source(idx, sub_idx);
+               dsrc->val |= (val == 1) ? P(OP, LOAD) : P(OP, STORE);
+       }
+}
+
+
 int isa207_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp)
 {
        unsigned int unit, pmc, cache, ebb;
index 899210f14ee432ea4b63cc7de6f7ea1a6da7a404..f711f337e35836303674c29e86db5144c1c61ea0 100644 (file)
 #define MAX_ALT                                2
 #define MAX_PMU_COUNTERS               6
 
+#define ISA207_SIER_TYPE_SHIFT         15
+#define ISA207_SIER_TYPE_MASK          (0x7ull << ISA207_SIER_TYPE_SHIFT)
+
+#define ISA207_SIER_LDST_SHIFT         1
+#define ISA207_SIER_LDST_MASK          (0x7ull << ISA207_SIER_LDST_SHIFT)
+
+#define ISA207_SIER_DATA_SRC_SHIFT     53
+#define ISA207_SIER_DATA_SRC_MASK      (0x7ull << ISA207_SIER_DATA_SRC_SHIFT)
+
+#define P(a, b)                                PERF_MEM_S(a, b)
+#define PH(a, b)                       (P(LVL, HIT) | P(a, b))
+#define PM(a, b)                       (P(LVL, MISS) | P(a, b))
+
 int isa207_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp);
 int isa207_compute_mmcr(u64 event[], int n_ev,
                                unsigned int hwc[], unsigned long mmcr[],
@@ -267,6 +280,7 @@ int isa207_compute_mmcr(u64 event[], int n_ev,
 void isa207_disable_pmc(unsigned int pmc, unsigned long mmcr[]);
 int isa207_get_alternatives(u64 event, u64 alt[],
                                const unsigned int ev_alt[][MAX_ALT], int size);
-
+void isa207_get_mem_data_src(union perf_mem_data_src *dsrc, u32 flags,
+                                                       struct pt_regs *regs);
 
 #endif