diff options
author | Stephane Eranian <eranian@google.com> | 2012-02-07 08:39:57 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2012-02-07 10:58:56 -0500 |
commit | f39d47ff819ed52a2afbdbecbe35f23f7755f58d (patch) | |
tree | 6fcd6c2b9f6e7416da43065d866bd40d68bb9bc4 /arch | |
parent | 136e0b8eabb2913b589fc7fbd418f4d6805dbb56 (diff) |
perf: Fix double start/stop in x86_pmu_start()
The following patch fixes a bug introduced by the following
commit:
e050e3f0a71b ("perf: Fix broken interrupt rate throttling")
The patch caused the following warning to pop up depending on
the sampling frequency adjustments:
------------[ cut here ]------------
WARNING: at arch/x86/kernel/cpu/perf_event.c:995 x86_pmu_start+0x79/0xd4()
It was caused by the following call sequence:
perf_adjust_freq_unthr_context.part() {
stop()
if (delta > 0) {
perf_adjust_period() {
if (period > 8*...) {
stop()
...
start()
}
}
}
start()
}
Which caused a double start and a double stop, thus triggering
the assert in x86_pmu_start().
The patch fixes the problem by avoiding the double calls. We
pass a new argument to perf_adjust_period() to indicate whether
or not the event is already stopped. We can't just remove the
start/stop from that function because it's called from
__perf_event_overflow where the event needs to be reloaded via a
stop/start back-toback call.
The patch reintroduces the assertion in x86_pmu_start() which
was removed by commit:
84f2b9b ("perf: Remove deprecated WARN_ON_ONCE()")
In this second version, we've added calls to disable/enable PMU
during unthrottling or frequency adjustment based on bug report
of spurious NMI interrupts from Eric Dumazet.
Reported-and-tested-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Stephane Eranian <eranian@google.com>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: markus@trippelsdorf.de
Cc: paulus@samba.org
Link: http://lkml.kernel.org/r/20120207133956.GA4932@quad
[ Minor edits to the changelog and to the code ]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 2a30e5ae6acf..5adce1040b11 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -986,6 +986,9 @@ static void x86_pmu_start(struct perf_event *event, int flags) | |||
986 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 986 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
987 | int idx = event->hw.idx; | 987 | int idx = event->hw.idx; |
988 | 988 | ||
989 | if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) | ||
990 | return; | ||
991 | |||
989 | if (WARN_ON_ONCE(idx == -1)) | 992 | if (WARN_ON_ONCE(idx == -1)) |
990 | return; | 993 | return; |
991 | 994 | ||