aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events
diff options
context:
space:
mode:
authorMark Rutland <mark.rutland@arm.com>2016-07-26 13:12:21 -0400
committerIngo Molnar <mingo@kernel.org>2016-08-10 07:13:23 -0400
commit3f005e7de3db8d0b3f7a1f399aa061dc35b65864 (patch)
tree71a91654d0b8f0181f544cd85eed6f24f8aa25dc /kernel/events
parentdb4a835601b73cf8d6cd8986381d966b8e13d2d9 (diff)
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 <mark.rutland@arm.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Arnaldo Carvalho de Melo <acme@kernel.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vince Weaver <vincent.weaver@maine.edu> Link: http://lkml.kernel.org/r/1469553141-28314-1-git-send-email-mark.rutland@arm.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/events')
-rw-r--r--kernel/events/core.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 1903b8f3a705..11f6bbe168ab 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -1796,6 +1796,8 @@ group_sched_out(struct perf_event *group_event,
1796 struct perf_event *event; 1796 struct perf_event *event;
1797 int state = group_event->state; 1797 int state = group_event->state;
1798 1798
1799 perf_pmu_disable(ctx->pmu);
1800
1799 event_sched_out(group_event, cpuctx, ctx); 1801 event_sched_out(group_event, cpuctx, ctx);
1800 1802
1801 /* 1803 /*
@@ -1804,6 +1806,8 @@ group_sched_out(struct perf_event *group_event,
1804 list_for_each_entry(event, &group_event->sibling_list, group_entry) 1806 list_for_each_entry(event, &group_event->sibling_list, group_entry)
1805 event_sched_out(event, cpuctx, ctx); 1807 event_sched_out(event, cpuctx, ctx);
1806 1808
1809 perf_pmu_enable(ctx->pmu);
1810
1807 if (state == PERF_EVENT_STATE_ACTIVE && group_event->attr.exclusive) 1811 if (state == PERF_EVENT_STATE_ACTIVE && group_event->attr.exclusive)
1808 cpuctx->exclusive = 0; 1812 cpuctx->exclusive = 0;
1809} 1813}