Commit 89a1e187 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar

perf: Provide a separate task context for swevents

Since software events are always schedulable, mixing them up with
hardware events (who are not) can lead to funny scheduling oddities.

Giving them their own context solves this.
Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Cc: paulus <paulus@samba.org>
Cc: stephane eranian <eranian@googlemail.com>
Cc: Robert Richter <robert.richter@amd.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Lin Ming <ming.m.lin@intel.com>
Cc: Yanmin <yanmin_zhang@linux.intel.com>
LKML-Reference: <new-submission>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 8dc85d54
No related merge requests found
...@@ -952,14 +952,7 @@ extern int perf_event_overflow(struct perf_event *event, int nmi, ...@@ -952,14 +952,7 @@ extern int perf_event_overflow(struct perf_event *event, int nmi,
*/ */
static inline int is_software_event(struct perf_event *event) static inline int is_software_event(struct perf_event *event)
{ {
switch (event->attr.type) { return event->pmu->task_ctx_nr == perf_sw_context;
case PERF_TYPE_SOFTWARE:
case PERF_TYPE_TRACEPOINT:
/* for now the breakpoint stuff also works as software event */
case PERF_TYPE_BREAKPOINT:
return 1;
}
return 0;
} }
extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
......
...@@ -1163,6 +1163,7 @@ struct rcu_node; ...@@ -1163,6 +1163,7 @@ struct rcu_node;
enum perf_event_task_context { enum perf_event_task_context {
perf_invalid_context = -1, perf_invalid_context = -1,
perf_hw_context = 0, perf_hw_context = 0,
perf_sw_context,
perf_nr_task_contexts, perf_nr_task_contexts,
}; };
......
...@@ -610,6 +610,8 @@ static void hw_breakpoint_stop(struct perf_event *bp, int flags) ...@@ -610,6 +610,8 @@ static void hw_breakpoint_stop(struct perf_event *bp, int flags)
} }
static struct pmu perf_breakpoint = { static struct pmu perf_breakpoint = {
.task_ctx_nr = perf_sw_context, /* could eventually get its own */
.event_init = hw_breakpoint_event_init, .event_init = hw_breakpoint_event_init,
.add = hw_breakpoint_add, .add = hw_breakpoint_add,
.del = hw_breakpoint_del, .del = hw_breakpoint_del,
......
...@@ -4709,6 +4709,8 @@ static int perf_swevent_init(struct perf_event *event) ...@@ -4709,6 +4709,8 @@ static int perf_swevent_init(struct perf_event *event)
} }
static struct pmu perf_swevent = { static struct pmu perf_swevent = {
.task_ctx_nr = perf_sw_context,
.event_init = perf_swevent_init, .event_init = perf_swevent_init,
.add = perf_swevent_add, .add = perf_swevent_add,
.del = perf_swevent_del, .del = perf_swevent_del,
...@@ -4800,6 +4802,8 @@ static int perf_tp_event_init(struct perf_event *event) ...@@ -4800,6 +4802,8 @@ static int perf_tp_event_init(struct perf_event *event)
} }
static struct pmu perf_tracepoint = { static struct pmu perf_tracepoint = {
.task_ctx_nr = perf_sw_context,
.event_init = perf_tp_event_init, .event_init = perf_tp_event_init,
.add = perf_trace_add, .add = perf_trace_add,
.del = perf_trace_del, .del = perf_trace_del,
...@@ -4988,6 +4992,8 @@ static int cpu_clock_event_init(struct perf_event *event) ...@@ -4988,6 +4992,8 @@ static int cpu_clock_event_init(struct perf_event *event)
} }
static struct pmu perf_cpu_clock = { static struct pmu perf_cpu_clock = {
.task_ctx_nr = perf_sw_context,
.event_init = cpu_clock_event_init, .event_init = cpu_clock_event_init,
.add = cpu_clock_event_add, .add = cpu_clock_event_add,
.del = cpu_clock_event_del, .del = cpu_clock_event_del,
...@@ -5063,6 +5069,8 @@ static int task_clock_event_init(struct perf_event *event) ...@@ -5063,6 +5069,8 @@ static int task_clock_event_init(struct perf_event *event)
} }
static struct pmu perf_task_clock = { static struct pmu perf_task_clock = {
.task_ctx_nr = perf_sw_context,
.event_init = task_clock_event_init, .event_init = task_clock_event_init,
.add = task_clock_event_add, .add = task_clock_event_add,
.del = task_clock_event_del, .del = task_clock_event_del,
...@@ -5490,6 +5498,7 @@ SYSCALL_DEFINE5(perf_event_open, ...@@ -5490,6 +5498,7 @@ SYSCALL_DEFINE5(perf_event_open,
struct perf_event_context *ctx; struct perf_event_context *ctx;
struct file *event_file = NULL; struct file *event_file = NULL;
struct file *group_file = NULL; struct file *group_file = NULL;
struct pmu *pmu;
int event_fd; int event_fd;
int fput_needed = 0; int fput_needed = 0;
int err; int err;
...@@ -5522,20 +5531,11 @@ SYSCALL_DEFINE5(perf_event_open, ...@@ -5522,20 +5531,11 @@ SYSCALL_DEFINE5(perf_event_open,
goto err_fd; goto err_fd;
} }
/*
* Get the target context (task or percpu):
*/
ctx = find_get_context(event->pmu, pid, cpu);
if (IS_ERR(ctx)) {
err = PTR_ERR(ctx);
goto err_alloc;
}
if (group_fd != -1) { if (group_fd != -1) {
group_leader = perf_fget_light(group_fd, &fput_needed); group_leader = perf_fget_light(group_fd, &fput_needed);
if (IS_ERR(group_leader)) { if (IS_ERR(group_leader)) {
err = PTR_ERR(group_leader); err = PTR_ERR(group_leader);
goto err_context; goto err_alloc;
} }
group_file = group_leader->filp; group_file = group_leader->filp;
if (flags & PERF_FLAG_FD_OUTPUT) if (flags & PERF_FLAG_FD_OUTPUT)
...@@ -5544,6 +5544,23 @@ SYSCALL_DEFINE5(perf_event_open, ...@@ -5544,6 +5544,23 @@ SYSCALL_DEFINE5(perf_event_open,
group_leader = NULL; group_leader = NULL;
} }
/*
* Special case software events and allow them to be part of
* any hardware group.
*/
pmu = event->pmu;
if ((pmu->task_ctx_nr == perf_sw_context) && group_leader)
pmu = group_leader->pmu;
/*
* Get the target context (task or percpu):
*/
ctx = find_get_context(pmu, pid, cpu);
if (IS_ERR(ctx)) {
err = PTR_ERR(ctx);
goto err_group_fd;
}
/* /*
* Look up the group leader (we will attach this event to it): * Look up the group leader (we will attach this event to it):
*/ */
...@@ -5605,8 +5622,9 @@ SYSCALL_DEFINE5(perf_event_open, ...@@ -5605,8 +5622,9 @@ SYSCALL_DEFINE5(perf_event_open,
return event_fd; return event_fd;
err_context: err_context:
fput_light(group_file, fput_needed);
put_ctx(ctx); put_ctx(ctx);
err_group_fd:
fput_light(group_file, fput_needed);
err_alloc: err_alloc:
free_event(event); free_event(event);
err_fd: err_fd:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment