Commit 4af57ef2 authored by Yan, Zheng's avatar Yan, Zheng Committed by Ingo Molnar

perf: Add pmu specific data for perf task context

Introduce a new flag PERF_ATTACH_TASK_DATA for perf event's attach
stata. The flag is set by PMU's event_init() callback, it indicates
that perf event needs PMU specific data.

The PMU specific data are initialized to zeros. Later patches will
use PMU specific data to save LBR stack.
Signed-off-by: default avatarYan, Zheng <zheng.z.yan@intel.com>
Signed-off-by: default avatarKan Liang <kan.liang@intel.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: eranian@google.com
Cc: jolsa@redhat.com
Link: http://lkml.kernel.org/r/1415156173-10035-6-git-send-email-kan.liang@intel.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent e9d7f7cd
...@@ -271,6 +271,10 @@ struct pmu { ...@@ -271,6 +271,10 @@ struct pmu {
*/ */
void (*sched_task) (struct perf_event_context *ctx, void (*sched_task) (struct perf_event_context *ctx,
bool sched_in); bool sched_in);
/*
* PMU specific data size
*/
size_t task_ctx_size;
}; };
...@@ -307,6 +311,7 @@ struct swevent_hlist { ...@@ -307,6 +311,7 @@ struct swevent_hlist {
#define PERF_ATTACH_CONTEXT 0x01 #define PERF_ATTACH_CONTEXT 0x01
#define PERF_ATTACH_GROUP 0x02 #define PERF_ATTACH_GROUP 0x02
#define PERF_ATTACH_TASK 0x04 #define PERF_ATTACH_TASK 0x04
#define PERF_ATTACH_TASK_DATA 0x08
struct perf_cgroup; struct perf_cgroup;
struct ring_buffer; struct ring_buffer;
...@@ -511,6 +516,7 @@ struct perf_event_context { ...@@ -511,6 +516,7 @@ struct perf_event_context {
u64 generation; u64 generation;
int pin_count; int pin_count;
int nr_cgroups; /* cgroup evts */ int nr_cgroups; /* cgroup evts */
void *task_ctx_data; /* pmu specific data */
struct rcu_head rcu_head; struct rcu_head rcu_head;
struct delayed_work orphans_remove; struct delayed_work orphans_remove;
......
...@@ -905,6 +905,15 @@ static void get_ctx(struct perf_event_context *ctx) ...@@ -905,6 +905,15 @@ static void get_ctx(struct perf_event_context *ctx)
WARN_ON(!atomic_inc_not_zero(&ctx->refcount)); WARN_ON(!atomic_inc_not_zero(&ctx->refcount));
} }
static void free_ctx(struct rcu_head *head)
{
struct perf_event_context *ctx;
ctx = container_of(head, struct perf_event_context, rcu_head);
kfree(ctx->task_ctx_data);
kfree(ctx);
}
static void put_ctx(struct perf_event_context *ctx) static void put_ctx(struct perf_event_context *ctx)
{ {
if (atomic_dec_and_test(&ctx->refcount)) { if (atomic_dec_and_test(&ctx->refcount)) {
...@@ -912,7 +921,7 @@ static void put_ctx(struct perf_event_context *ctx) ...@@ -912,7 +921,7 @@ static void put_ctx(struct perf_event_context *ctx)
put_ctx(ctx->parent_ctx); put_ctx(ctx->parent_ctx);
if (ctx->task) if (ctx->task)
put_task_struct(ctx->task); put_task_struct(ctx->task);
kfree_rcu(ctx, rcu_head); call_rcu(&ctx->rcu_head, free_ctx);
} }
} }
...@@ -3309,12 +3318,15 @@ find_lively_task_by_vpid(pid_t vpid) ...@@ -3309,12 +3318,15 @@ find_lively_task_by_vpid(pid_t vpid)
* Returns a matching context with refcount and pincount. * Returns a matching context with refcount and pincount.
*/ */
static struct perf_event_context * static struct perf_event_context *
find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) find_get_context(struct pmu *pmu, struct task_struct *task,
struct perf_event *event)
{ {
struct perf_event_context *ctx, *clone_ctx = NULL; struct perf_event_context *ctx, *clone_ctx = NULL;
struct perf_cpu_context *cpuctx; struct perf_cpu_context *cpuctx;
void *task_ctx_data = NULL;
unsigned long flags; unsigned long flags;
int ctxn, err; int ctxn, err;
int cpu = event->cpu;
if (!task) { if (!task) {
/* Must be root to operate on a CPU event: */ /* Must be root to operate on a CPU event: */
...@@ -3342,11 +3354,24 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) ...@@ -3342,11 +3354,24 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu)
if (ctxn < 0) if (ctxn < 0)
goto errout; goto errout;
if (event->attach_state & PERF_ATTACH_TASK_DATA) {
task_ctx_data = kzalloc(pmu->task_ctx_size, GFP_KERNEL);
if (!task_ctx_data) {
err = -ENOMEM;
goto errout;
}
}
retry: retry:
ctx = perf_lock_task_context(task, ctxn, &flags); ctx = perf_lock_task_context(task, ctxn, &flags);
if (ctx) { if (ctx) {
clone_ctx = unclone_ctx(ctx); clone_ctx = unclone_ctx(ctx);
++ctx->pin_count; ++ctx->pin_count;
if (task_ctx_data && !ctx->task_ctx_data) {
ctx->task_ctx_data = task_ctx_data;
task_ctx_data = NULL;
}
raw_spin_unlock_irqrestore(&ctx->lock, flags); raw_spin_unlock_irqrestore(&ctx->lock, flags);
if (clone_ctx) if (clone_ctx)
...@@ -3357,6 +3382,11 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) ...@@ -3357,6 +3382,11 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu)
if (!ctx) if (!ctx)
goto errout; goto errout;
if (task_ctx_data) {
ctx->task_ctx_data = task_ctx_data;
task_ctx_data = NULL;
}
err = 0; err = 0;
mutex_lock(&task->perf_event_mutex); mutex_lock(&task->perf_event_mutex);
/* /*
...@@ -3383,9 +3413,11 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) ...@@ -3383,9 +3413,11 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu)
} }
} }
kfree(task_ctx_data);
return ctx; return ctx;
errout: errout:
kfree(task_ctx_data);
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -7559,7 +7591,7 @@ SYSCALL_DEFINE5(perf_event_open, ...@@ -7559,7 +7591,7 @@ SYSCALL_DEFINE5(perf_event_open,
/* /*
* Get the target context (task or percpu): * Get the target context (task or percpu):
*/ */
ctx = find_get_context(pmu, task, event->cpu); ctx = find_get_context(pmu, task, event);
if (IS_ERR(ctx)) { if (IS_ERR(ctx)) {
err = PTR_ERR(ctx); err = PTR_ERR(ctx);
goto err_alloc; goto err_alloc;
...@@ -7765,7 +7797,7 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, ...@@ -7765,7 +7797,7 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
account_event(event); account_event(event);
ctx = find_get_context(event->pmu, task, cpu); ctx = find_get_context(event->pmu, task, event);
if (IS_ERR(ctx)) { if (IS_ERR(ctx)) {
err = PTR_ERR(ctx); err = PTR_ERR(ctx);
goto err_free; goto err_free;
......
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