Skip to content

Commit

Permalink
perf: Provide a separate task context for swevents
Browse files Browse the repository at this point in the history
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: Peter 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: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Peter Zijlstra authored and Ingo Molnar committed Sep 9, 2010
1 parent 8dc85d5 commit 89a1e18
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 19 deletions.
9 changes: 1 addition & 8 deletions include/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
switch (event->attr.type) {
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;
return event->pmu->task_ctx_nr == perf_sw_context;
}

extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
Expand Down
1 change: 1 addition & 0 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,7 @@ struct rcu_node;
enum perf_event_task_context {
perf_invalid_context = -1,
perf_hw_context = 0,
perf_sw_context,
perf_nr_task_contexts,
};

Expand Down
2 changes: 2 additions & 0 deletions kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,8 @@ static void hw_breakpoint_stop(struct perf_event *bp, int flags)
}

static struct pmu perf_breakpoint = {
.task_ctx_nr = perf_sw_context, /* could eventually get its own */

.event_init = hw_breakpoint_event_init,
.add = hw_breakpoint_add,
.del = hw_breakpoint_del,
Expand Down
40 changes: 29 additions & 11 deletions kernel/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -4709,6 +4709,8 @@ static int perf_swevent_init(struct perf_event *event)
}

static struct pmu perf_swevent = {
.task_ctx_nr = perf_sw_context,

.event_init = perf_swevent_init,
.add = perf_swevent_add,
.del = perf_swevent_del,
Expand Down Expand Up @@ -4800,6 +4802,8 @@ static int perf_tp_event_init(struct perf_event *event)
}

static struct pmu perf_tracepoint = {
.task_ctx_nr = perf_sw_context,

.event_init = perf_tp_event_init,
.add = perf_trace_add,
.del = perf_trace_del,
Expand Down Expand Up @@ -4988,6 +4992,8 @@ static int cpu_clock_event_init(struct perf_event *event)
}

static struct pmu perf_cpu_clock = {
.task_ctx_nr = perf_sw_context,

.event_init = cpu_clock_event_init,
.add = cpu_clock_event_add,
.del = cpu_clock_event_del,
Expand Down Expand Up @@ -5063,6 +5069,8 @@ static int task_clock_event_init(struct perf_event *event)
}

static struct pmu perf_task_clock = {
.task_ctx_nr = perf_sw_context,

.event_init = task_clock_event_init,
.add = task_clock_event_add,
.del = task_clock_event_del,
Expand Down Expand Up @@ -5490,6 +5498,7 @@ SYSCALL_DEFINE5(perf_event_open,
struct perf_event_context *ctx;
struct file *event_file = NULL;
struct file *group_file = NULL;
struct pmu *pmu;
int event_fd;
int fput_needed = 0;
int err;
Expand Down Expand Up @@ -5522,20 +5531,11 @@ SYSCALL_DEFINE5(perf_event_open,
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) {
group_leader = perf_fget_light(group_fd, &fput_needed);
if (IS_ERR(group_leader)) {
err = PTR_ERR(group_leader);
goto err_context;
goto err_alloc;
}
group_file = group_leader->filp;
if (flags & PERF_FLAG_FD_OUTPUT)
Expand All @@ -5544,6 +5544,23 @@ SYSCALL_DEFINE5(perf_event_open,
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):
*/
Expand Down Expand Up @@ -5605,8 +5622,9 @@ SYSCALL_DEFINE5(perf_event_open,
return event_fd;

err_context:
fput_light(group_file, fput_needed);
put_ctx(ctx);
err_group_fd:
fput_light(group_file, fput_needed);
err_alloc:
free_event(event);
err_fd:
Expand Down

0 comments on commit 89a1e18

Please sign in to comment.