[RFC 04/11] powerpc/perf: Arch support to expose Hazard data
Ravi Bangoria
ravi.bangoria at linux.ibm.com
Mon Mar 2 16:23:48 AEDT 2020
From: Madhavan Srinivasan <maddy at linux.vnet.ibm.com>
SIER register on PowerPC hw pmu provides cpu pipeline hazard information.
Add logic to convert this arch specific data into perf_pipeline_haz_data
structure.
Signed-off-by: Madhavan Srinivasan <maddy at linux.vnet.ibm.com>
Signed-off-by: Ravi Bangoria <ravi.bangoria at linux.ibm.com>
---
arch/powerpc/include/asm/perf_event_server.h | 2 +
arch/powerpc/perf/core-book3s.c | 4 +
arch/powerpc/perf/isa207-common.c | 157 +++++++++++++++++++
arch/powerpc/perf/isa207-common.h | 12 ++
arch/powerpc/perf/power8-pmu.c | 1 +
arch/powerpc/perf/power9-pmu.c | 1 +
6 files changed, 177 insertions(+)
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h
index 3e9703f44c7c..9b8f90439ff2 100644
--- a/arch/powerpc/include/asm/perf_event_server.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -37,6 +37,8 @@ struct power_pmu {
void (*get_mem_data_src)(union perf_mem_data_src *dsrc,
u32 flags, struct pt_regs *regs);
void (*get_mem_weight)(u64 *weight);
+ void (*get_phazard_data)(struct perf_pipeline_haz_data *phaz,
+ u32 flags, struct pt_regs *regs);
unsigned long group_constraint_mask;
unsigned long group_constraint_val;
u64 (*bhrb_filter_map)(u64 branch_sample_type);
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 3086055bf681..fcbb4acc3a03 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -2096,6 +2096,10 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
ppmu->get_mem_weight)
ppmu->get_mem_weight(&data.weight);
+ if (event->attr.sample_type & PERF_SAMPLE_PIPELINE_HAZ &&
+ ppmu->get_phazard_data)
+ ppmu->get_phazard_data(&data.pipeline_haz, ppmu->flags, regs);
+
if (perf_event_overflow(event, &data, regs))
power_pmu_stop(event, 0);
}
diff --git a/arch/powerpc/perf/isa207-common.c b/arch/powerpc/perf/isa207-common.c
index 07026bbd292b..03dafde7cace 100644
--- a/arch/powerpc/perf/isa207-common.c
+++ b/arch/powerpc/perf/isa207-common.c
@@ -239,6 +239,163 @@ void isa207_get_mem_weight(u64 *weight)
*weight = mantissa << (2 * exp);
}
+static __u8 get_inst_type(u64 sier)
+{
+ switch (SIER_TYPE(sier)) {
+ case 1:
+ return PERF_HAZ__ITYPE_LOAD;
+ case 2:
+ return PERF_HAZ__ITYPE_STORE;
+ case 3:
+ return PERF_HAZ__ITYPE_BRANCH;
+ case 4:
+ return PERF_HAZ__ITYPE_FP;
+ case 5:
+ return PERF_HAZ__ITYPE_FX;
+ case 6:
+ return PERF_HAZ__ITYPE_CR_OR_SC;
+ }
+ return PERF_HAZ__ITYPE_NA;
+}
+
+static __u8 get_inst_cache(u64 sier)
+{
+ switch (SIER_ICACHE(sier)) {
+ case 1:
+ return PERF_HAZ__ICACHE_L1_HIT;
+ case 2:
+ return PERF_HAZ__ICACHE_L2_HIT;
+ case 3:
+ return PERF_HAZ__ICACHE_L3_HIT;
+ case 4:
+ return PERF_HAZ__ICACHE_L3_MISS;
+ }
+ return PERF_HAZ__ICACHE_NA;
+}
+
+static void get_hazard_data(u64 sier, struct perf_pipeline_haz_data *haz)
+{
+ if (SIER_MPRED(sier)) {
+ haz->hazard_stage = PERF_HAZ__PIPE_STAGE_BRU;
+
+ switch (SIER_MPRED_TYPE(sier)) {
+ case 1:
+ haz->hazard_reason = PERF_HAZ__HAZ_BRU_MPRED_DIR;
+ return;
+ case 2:
+ haz->hazard_reason = PERF_HAZ__HAZ_BRU_MPRED_TA;
+ return;
+ }
+ }
+
+ if (cpu_has_feature(CPU_FTR_ARCH_300) &&
+ (SIER_TYPE(sier) == 1 || SIER_TYPE(sier) == 2)) {
+ haz->hazard_stage = PERF_HAZ__PIPE_STAGE_LSU;
+ haz->hazard_reason = PERF_HAZ__HAZ_DERAT_MISS;
+ return;
+ }
+
+ if (cpu_has_feature(CPU_FTR_ARCH_207S) &&
+ (SIER_TYPE(sier) == 1 || SIER_TYPE(sier) == 2)) {
+ int derat_miss = SIER_DERAT_MISS(sier);
+
+ haz->hazard_stage = PERF_HAZ__PIPE_STAGE_LSU;
+
+ switch (p8_SIER_REJ_LSU_REASON(sier)) {
+ case 0:
+ haz->hazard_reason = PERF_HAZ__HAZ_LSU_ERAT_MISS;
+ return;
+ case 1:
+ haz->hazard_reason = (derat_miss) ?
+ PERF_HAZ__HAZ_LSU_LMQ_DERAT_MISS :
+ PERF_HAZ__HAZ_LSU_LMQ;
+ return;
+ case 2:
+ haz->hazard_reason = (derat_miss) ?
+ PERF_HAZ__HAZ_LSU_LHS_DERAT_MISS :
+ PERF_HAZ__HAZ_LSU_LHS;
+ return;
+ case 3:
+ haz->hazard_reason = (derat_miss) ?
+ PERF_HAZ__HAZ_LSU_MPRED_DERAT_MISS :
+ PERF_HAZ__HAZ_LSU_MPRED;
+ return;
+ }
+
+ if (derat_miss)
+ haz->hazard_reason = PERF_HAZ__HAZ_DERAT_MISS;
+ }
+
+ if (cpu_has_feature(CPU_FTR_ARCH_207S) && p8_SIER_REJ_ISU(sier)) {
+ haz->hazard_stage = PERF_HAZ__PIPE_STAGE_ISU;
+
+ if (p8_SIER_REJ_ISU_SRC(sier))
+ haz->hazard_reason = PERF_HAZ__HAZ_ISU_SRC;
+ if (p8_SIER_REJ_ISU_COL(sier))
+ haz->hazard_reason = PERF_HAZ__HAZ_ISU_COL;
+ }
+}
+
+static void get_stall_data(u64 sier, struct perf_pipeline_haz_data *haz)
+{
+ switch (SIER_FIN_STALL_REASON(sier)) {
+ case 1:
+ haz->stall_stage = PERF_HAZ__PIPE_STAGE_OTHER;
+ haz->stall_reason = PERF_HAZ__STALL_NTC;
+ break;
+ case 4:
+ haz->stall_stage = PERF_HAZ__PIPE_STAGE_LSU;
+ haz->stall_reason = PERF_HAZ__STALL_LSU_DCACHE_MISS;
+ break;
+ case 5:
+ haz->stall_stage = PERF_HAZ__PIPE_STAGE_LSU;
+ haz->stall_reason = PERF_HAZ__STALL_LSU_LD_FIN;
+ break;
+ case 6:
+ haz->stall_stage = PERF_HAZ__PIPE_STAGE_LSU;
+ haz->stall_reason = PERF_HAZ__STALL_LSU_ST_FWD;
+ break;
+ case 7:
+ haz->stall_stage = PERF_HAZ__PIPE_STAGE_LSU;
+ haz->stall_reason = PERF_HAZ__STALL_LSU_ST;
+ break;
+ case 8:
+ haz->stall_stage = PERF_HAZ__PIPE_STAGE_FXU;
+ haz->stall_reason = PERF_HAZ__STALL_FXU_MC;
+ break;
+ case 9:
+ haz->stall_stage = PERF_HAZ__PIPE_STAGE_BRU;
+ haz->stall_reason = PERF_HAZ__STALL_BRU_FIN_MPRED;
+ break;
+ case 10:
+ haz->stall_stage = PERF_HAZ__PIPE_STAGE_VSU;
+ haz->stall_reason = PERF_HAZ__STALL_VSU_MC;
+ break;
+ case 12:
+ haz->stall_stage = PERF_HAZ__PIPE_STAGE_FXU;
+ haz->stall_reason = PERF_HAZ__STALL_FXU_FC;
+ break;
+ case 13:
+ haz->stall_stage = PERF_HAZ__PIPE_STAGE_VSU;
+ haz->stall_reason = PERF_HAZ__STALL_VSU_FC;
+ break;
+ case 14:
+ haz->stall_stage = PERF_HAZ__PIPE_STAGE_BRU;
+ haz->stall_reason = PERF_HAZ__STALL_BRU_FC;
+ }
+}
+
+void isa207_get_phazard_data(struct perf_pipeline_haz_data *haz, u32 flags,
+ struct pt_regs *regs)
+{
+ u64 sier = mfspr(SPRN_SIER);
+
+ haz->itype = get_inst_type(sier);
+ haz->icache = get_inst_cache(sier);
+ get_hazard_data(sier, haz);
+ get_stall_data(sier, haz);
+}
+
int isa207_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp)
{
unsigned int unit, pmc, cache, ebb;
diff --git a/arch/powerpc/perf/isa207-common.h b/arch/powerpc/perf/isa207-common.h
index 7027eb9f3e40..125e0e44aeea 100644
--- a/arch/powerpc/perf/isa207-common.h
+++ b/arch/powerpc/perf/isa207-common.h
@@ -12,6 +12,7 @@
#include <linux/perf_event.h>
#include <asm/firmware.h>
#include <asm/cputable.h>
+#include <asm/perf_pipeline_haz.h>
#define EVENT_EBB_MASK 1ull
#define EVENT_EBB_SHIFT PERF_EVENT_CONFIG_EBB_SHIFT
@@ -202,8 +203,17 @@
#define MAX_ALT 2
#define MAX_PMU_COUNTERS 6
+#define SIER_FIN_STALL_REASON(sier) (((sier) >> (63 - 6)) & 0xfull)
#define SIER_DATA_SRC(sier) (((sier) >> (63 - 10)) & 0x7ull)
+#define p8_SIER_REJ_ISU_SRC(sier) (((sier) >> (63 - 32)) & 0x1ull)
+#define p8_SIER_REJ_ISU_COL(sier) (((sier) >> (63 - 33)) & 0x1ull)
+#define p8_SIER_REJ_ISU(sier) (((sier) >> (63 - 33)) & 0x3ull)
+#define p8_SIER_REJ_LSU_REASON(sier) (((sier) >> (63 - 36)) & 0x3ull)
#define SIER_TYPE(sier) (((sier) >> (63 - 48)) & 0x7ull)
+#define SIER_ICACHE(sier) (((sier) >> (63 - 51)) & 0x7ull)
+#define SIER_MPRED(sier) (((sier) >> (63 - 53)) & 0x1ull)
+#define SIER_MPRED_TYPE(sier) (((sier) >> (63 - 55)) & 0x3ull)
+#define SIER_DERAT_MISS(sier) (((sier) >> (63 - 56)) & 0x1ull)
#define SIER_LDST(sier) (((sier) >> (63 - 62)) & 0x7ull)
#define P(a, b) PERF_MEM_S(a, b)
@@ -220,5 +230,7 @@ int isa207_get_alternatives(u64 event, u64 alt[], int size, unsigned int flags,
void isa207_get_mem_data_src(union perf_mem_data_src *dsrc, u32 flags,
struct pt_regs *regs);
void isa207_get_mem_weight(u64 *weight);
+void isa207_get_phazard_data(struct perf_pipeline_haz_data *haz, u32 flags,
+ struct pt_regs *regs);
#endif
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index 3a5fcc20ff31..dc407329ba94 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -370,6 +370,7 @@ static struct power_pmu power8_pmu = {
.get_mem_data_src = isa207_get_mem_data_src,
.get_mem_weight = isa207_get_mem_weight,
.disable_pmc = isa207_disable_pmc,
+ .get_phazard_data = isa207_get_phazard_data,
.flags = PPMU_HAS_SIER | PPMU_ARCH_207S,
.n_generic = ARRAY_SIZE(power8_generic_events),
.generic_events = power8_generic_events,
diff --git a/arch/powerpc/perf/power9-pmu.c b/arch/powerpc/perf/power9-pmu.c
index 08c3ef796198..84f663d8df13 100644
--- a/arch/powerpc/perf/power9-pmu.c
+++ b/arch/powerpc/perf/power9-pmu.c
@@ -428,6 +428,7 @@ static struct power_pmu power9_pmu = {
.get_mem_data_src = isa207_get_mem_data_src,
.get_mem_weight = isa207_get_mem_weight,
.disable_pmc = isa207_disable_pmc,
+ .get_phazard_data = isa207_get_phazard_data,
.flags = PPMU_HAS_SIER | PPMU_ARCH_207S,
.n_generic = ARRAY_SIZE(power9_generic_events),
.generic_events = power9_generic_events,
--
2.21.1
More information about the Linuxppc-dev
mailing list