perf/core: Sched out groups atomically

This change “perf/core: Sched out groups atomically” in Linux kernel is authored by Mark Rutland <mark.rutland [at]> on Tue Jul 26 18:12:21 2016 +0100.

perf/core: Sched out groups atomically

Groups of events are supposed to be scheduled atomically, such that it
is possible to derive meaningful ratios between their values.

We take great pains to achieve this when scheduling event groups to a
PMU in group_sched_in(), calling {start,commit}_txn() (which fall back
to perf_pmu_{disable,enable}() if necessary) to provide this guarantee.
However we don't mirror this in group_sched_out(), and in some cases
events will not be scheduled out atomically.

For example, if we disable an event group with PERF_EVENT_IOC_DISABLE,
we'll cross-call __perf_event_disable() for the group leader, and will
call group_sched_out() without having first disabled the relevant PMU.
We will disable/enable the PMU around each pmu->del() call, but between
each call the PMU will be enabled and events may count.

Avoid this by explicitly disabling and enabling the PMU around event
removal in group_sched_out(), mirroring what we do in group_sched_in().

Signed-off-by: Mark Rutland <>
Signed-off-by: Peter Zijlstra (Intel) <>
Cc: Alexander Shishkin <>
Cc: Arnaldo Carvalho de Melo <>
Cc: Arnaldo Carvalho de Melo <>
Cc: Jiri Olsa <>
Cc: Linus Torvalds <>
Cc: Peter Zijlstra <>
Cc: Stephane Eranian <>
Cc: Thomas Gleixner <>
Cc: Vince Weaver <>
Signed-off-by: Ingo Molnar <>

This Linux change may have been applied to various maintained Linux releases and you can find Linux releases including commit 3f005e7.

There are 4 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 kernel/events/core.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/kernel/events/core.c b/kernel/events/core.c
index 1903b8f..11f6bbe 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -1796,6 +1796,8 @@ static inline int pmu_filter_match(struct perf_event *event)
 	struct perf_event *event;
 	int state = group_event->state;
+	perf_pmu_disable(ctx->pmu);
 	event_sched_out(group_event, cpuctx, ctx);
@@ -1804,6 +1806,8 @@ static inline int pmu_filter_match(struct perf_event *event)
 	list_for_each_entry(event, &group_event->sibling_list, group_entry)
 		event_sched_out(event, cpuctx, ctx);
+	perf_pmu_enable(ctx->pmu);
 	if (state == PERF_EVENT_STATE_ACTIVE && group_event->attr.exclusive)
 		cpuctx->exclusive = 0;

The commit for this change in Linux stable tree is 3f005e7 (patch).

Leave a Reply

Your email address will not be published. Required fields are marked *