perf, x86: P4 PMU -- handle unflagged events
It might happen that an event can overflow without the proper overflow flag set. Check the sign bit in the raw counter value to solve this problem. Tested-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: fweisbec@gmail.com Cc: Cyrill Gorcunov <gorcunov@gmail.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> LKML-Reference: <1274083984.6540.15.camel@minggr.sh.intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
32ec6acfdc
commit
0db1a7bc00
|
@ -465,15 +465,21 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static inline void p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
|
||||
static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
|
||||
{
|
||||
unsigned long dummy;
|
||||
int overflow = 0;
|
||||
u32 low, high;
|
||||
|
||||
rdmsrl(hwc->config_base + hwc->idx, dummy);
|
||||
if (dummy & P4_CCCR_OVF) {
|
||||
rdmsr(hwc->config_base + hwc->idx, low, high);
|
||||
|
||||
/* we need to check high bit for unflagged overflows */
|
||||
if ((low & P4_CCCR_OVF) || (high & (1 << 31))) {
|
||||
overflow = 1;
|
||||
(void)checking_wrmsrl(hwc->config_base + hwc->idx,
|
||||
((u64)dummy) & ~P4_CCCR_OVF);
|
||||
((u64)low) & ~P4_CCCR_OVF);
|
||||
}
|
||||
|
||||
return overflow;
|
||||
}
|
||||
|
||||
static inline void p4_pmu_disable_event(struct perf_event *event)
|
||||
|
@ -584,21 +590,15 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
|
|||
|
||||
WARN_ON_ONCE(hwc->idx != idx);
|
||||
|
||||
/*
|
||||
* FIXME: Redundant call, actually not needed
|
||||
* but just to check if we're screwed
|
||||
*/
|
||||
p4_pmu_clear_cccr_ovf(hwc);
|
||||
/* it might be unflagged overflow */
|
||||
handled = p4_pmu_clear_cccr_ovf(hwc);
|
||||
|
||||
val = x86_perf_event_update(event);
|
||||
if (val & (1ULL << (x86_pmu.cntval_bits - 1)))
|
||||
if (!handled && (val & (1ULL << (x86_pmu.cntval_bits - 1))))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* event overflow
|
||||
*/
|
||||
handled = 1;
|
||||
data.period = event->hw.last_period;
|
||||
/* event overflow for sure */
|
||||
data.period = event->hw.last_period;
|
||||
|
||||
if (!x86_perf_event_set_period(event))
|
||||
continue;
|
||||
|
|
Loading…
Reference in a new issue