perf: allow for PMU-specific event filtering
In certain circumstances it may not be possible to schedule particular events due to constraints other than a lack of hardware counters (e.g. on big.LITTLE systems where CPUs support different events). The core perf event code does not distinguish these cases and pessimistically assumes that any failure to schedule an event means that it is not worth attempting to schedule later events, even if some hardware counters are still unused. When an event a pmu cannot schedule exists in a flexible group list it can unnecessarily prevent event groups following it in the list from being scheduled (until it is rotated to the end of the list). This means some events are scheduled for only a portion of the time they could be, and for short running programs no events may be scheduled if the list is initially sorted in an unfortunate order. This patch adds a new (optional) filter_match function pointer to struct pmu which a pmu driver can use to tell perf core when an event matches pmu-specific scheduling requirements. This plugs into the existing event_filter_match logic, and makes it possible to avoid the scheduling problem described above. When no filter is provided by the PMU, the existing behaviour is retained. Cc: Paul Mackerras <paulus@samba.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Arnaldo Carvalho de Melo <acme@kernel.org> Acked-by: Will Deacon <will.deacon@arm.com> Acked-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
Родитель
b787f68c36
Коммит
66eb579e66
|
@ -304,6 +304,11 @@ struct pmu {
|
|||
* Free pmu-private AUX data structures
|
||||
*/
|
||||
void (*free_aux) (void *aux); /* optional */
|
||||
|
||||
/*
|
||||
* Filter events for PMU-specific reasons.
|
||||
*/
|
||||
int (*filter_match) (struct perf_event *event); /* optional */
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1506,11 +1506,17 @@ static int __init perf_workqueue_init(void)
|
|||
|
||||
core_initcall(perf_workqueue_init);
|
||||
|
||||
static inline int pmu_filter_match(struct perf_event *event)
|
||||
{
|
||||
struct pmu *pmu = event->pmu;
|
||||
return pmu->filter_match ? pmu->filter_match(event) : 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
event_filter_match(struct perf_event *event)
|
||||
{
|
||||
return (event->cpu == -1 || event->cpu == smp_processor_id())
|
||||
&& perf_cgroup_match(event);
|
||||
&& perf_cgroup_match(event) && pmu_filter_match(event);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Загрузка…
Ссылка в новой задаче