perf_counter: unify and fix delayed counter wakeup
While going over the wakeup code I noticed delayed wakeups only work for hardware counters but basically all software counters rely on them. This patch unifies and generalizes the delayed wakeup to fix this issue. Since we're dealing with NMI context bits here, use a cmpxchg() based single link list implementation to track counters that have pending wakeups. [ This should really be generic code for delayed wakeups, but since we cannot use cmpxchg()/xchg() in generic code, I've let it live in the perf_counter code. -- Eric Dumazet could use it to aggregate the network wakeups. ] Furthermore, the x86 method of using TIF flags was flawed in that its quite possible to end up setting the bit on the idle task, loosing the wakeup. The powerpc method uses per-cpu storage and does appear to be sufficient. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Acked-by: Paul Mackerras <paulus@samba.org> Orig-LKML-Reference: <20090330171023.153932974@chello.nl> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:

committed by
Ingo Molnar

parent
53cfbf5937
commit
925d519ab8
@@ -227,7 +227,6 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
|
||||
*/
|
||||
hwc->config |= pmc_ops->event_map(perf_event_id(hw_event));
|
||||
}
|
||||
counter->wakeup_pending = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -773,34 +772,6 @@ void smp_perf_counter_interrupt(struct pt_regs *regs)
|
||||
irq_exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* This handler is triggered by NMI contexts:
|
||||
*/
|
||||
void perf_counter_notify(struct pt_regs *regs)
|
||||
{
|
||||
struct cpu_hw_counters *cpuc;
|
||||
unsigned long flags;
|
||||
int bit, cpu;
|
||||
|
||||
local_irq_save(flags);
|
||||
cpu = smp_processor_id();
|
||||
cpuc = &per_cpu(cpu_hw_counters, cpu);
|
||||
|
||||
for_each_bit(bit, cpuc->used, X86_PMC_IDX_MAX) {
|
||||
struct perf_counter *counter = cpuc->counters[bit];
|
||||
|
||||
if (!counter)
|
||||
continue;
|
||||
|
||||
if (counter->wakeup_pending) {
|
||||
counter->wakeup_pending = 0;
|
||||
wake_up(&counter->waitq);
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void perf_counters_lapic_init(int nmi)
|
||||
{
|
||||
u32 apic_val;
|
||||
|
@@ -6,7 +6,6 @@
|
||||
* 2000-06-20 Pentium III FXSR, SSE support by Gareth Hughes
|
||||
* 2000-2002 x86-64 support by Andi Kleen
|
||||
*/
|
||||
#include <linux/perf_counter.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/smp.h>
|
||||
@@ -872,11 +871,6 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
|
||||
tracehook_notify_resume(regs);
|
||||
}
|
||||
|
||||
if (thread_info_flags & _TIF_PERF_COUNTERS) {
|
||||
clear_thread_flag(TIF_PERF_COUNTERS);
|
||||
perf_counter_notify(regs);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
clear_thread_flag(TIF_IRET);
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
Reference in New Issue
Block a user