powerpc/perf: Sample only if SIAR-Valid bit is set in P7+
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>
This commit is contained in:
parent
e8294de53b
commit
e6878835ac
|
@ -49,6 +49,7 @@ struct power_pmu {
|
||||||
#define PPMU_ALT_SIPR 2 /* uses alternate posn for SIPR/HV */
|
#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_SIPR 4 /* no SIPR/HV in MMCRA at all */
|
||||||
#define PPMU_NO_CONT_SAMPLING 8 /* no continuous sampling */
|
#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()
|
* Values for flags to get_alternatives()
|
||||||
|
|
|
@ -606,6 +606,10 @@
|
||||||
#define POWER6_MMCRA_SIPR 0x0000020000000000ULL
|
#define POWER6_MMCRA_SIPR 0x0000020000000000ULL
|
||||||
#define POWER6_MMCRA_THRM 0x00000020UL
|
#define POWER6_MMCRA_THRM 0x00000020UL
|
||||||
#define POWER6_MMCRA_OTHER 0x0000000EUL
|
#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_PMC1 787
|
||||||
#define SPRN_PMC2 788
|
#define SPRN_PMC2 788
|
||||||
#define SPRN_PMC3 789
|
#define SPRN_PMC3 789
|
||||||
|
|
|
@ -82,6 +82,11 @@ static inline int perf_intr_is_nmi(struct pt_regs *regs)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int siar_valid(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_PPC32 */
|
#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
|
* If we're not doing instruction sampling, give them the SDAR
|
||||||
* (sampled data address). If we are doing instruction sampling, then
|
* (sampled data address). If we are doing instruction sampling, then
|
||||||
* only give them the SDAR if it corresponds to the instruction
|
* only give them the SDAR if it corresponds to the instruction
|
||||||
* pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC
|
* pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC or
|
||||||
* bit in MMCRA.
|
* the [POWER7P_]MMCRA_SDAR_VALID bit in MMCRA.
|
||||||
*/
|
*/
|
||||||
static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
|
static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
|
||||||
{
|
{
|
||||||
unsigned long mmcra = regs->dsisr;
|
unsigned long mmcra = regs->dsisr;
|
||||||
unsigned long sdsync = (ppmu->flags & PPMU_ALT_SIPR) ?
|
unsigned long sdsync;
|
||||||
POWER6_MMCRA_SDSYNC : MMCRA_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))
|
if (!(mmcra & MMCRA_SAMPLE_ENABLE) || (mmcra & sdsync))
|
||||||
*addrp = mfspr(SPRN_SDAR);
|
*addrp = mfspr(SPRN_SDAR);
|
||||||
|
@ -230,6 +241,24 @@ static inline int perf_intr_is_nmi(struct pt_regs *regs)
|
||||||
return !regs->softe;
|
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 */
|
#endif /* CONFIG_PPC64 */
|
||||||
|
|
||||||
static void perf_event_interrupt(struct pt_regs *regs);
|
static void perf_event_interrupt(struct pt_regs *regs);
|
||||||
|
@ -1291,6 +1320,7 @@ struct pmu power_pmu = {
|
||||||
.event_idx = power_pmu_event_idx,
|
.event_idx = power_pmu_event_idx,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A counter has overflowed; update its count and record
|
* A counter has overflowed; update its count and record
|
||||||
* things if requested. Note that interrupts are hard-disabled
|
* 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;
|
left += period;
|
||||||
if (left <= 0)
|
if (left <= 0)
|
||||||
left = period;
|
left = period;
|
||||||
record = 1;
|
record = siar_valid(regs);
|
||||||
event->hw.last_period = event->hw.sample_period;
|
event->hw.last_period = event->hw.sample_period;
|
||||||
}
|
}
|
||||||
if (left < 0x80000000LL)
|
if (left < 0x80000000LL)
|
||||||
|
@ -1374,8 +1404,10 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned long use_siar = regs->result;
|
unsigned long use_siar = regs->result;
|
||||||
|
|
||||||
if (use_siar)
|
if (use_siar && siar_valid(regs))
|
||||||
return mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
|
return mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
|
||||||
|
else if (use_siar)
|
||||||
|
return 0; // no valid instruction pointer
|
||||||
else
|
else
|
||||||
return regs->nip;
|
return regs->nip;
|
||||||
}
|
}
|
||||||
|
|
|
@ -373,6 +373,9 @@ static int __init init_power7_pmu(void)
|
||||||
strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7"))
|
strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7"))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (pvr_version_is(PVR_POWER7p))
|
||||||
|
power7_pmu.flags |= PPMU_SIAR_VALID;
|
||||||
|
|
||||||
return register_power_pmu(&power7_pmu);
|
return register_power_pmu(&power7_pmu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue