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: Yan, Zheng <zheng.z.yan@intel.com> Signed-off-by: Kan Liang <kan.liang@intel.com> Signed-off-by: Peter 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.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Родитель
e9d7f7cd97
Коммит
4af57ef28c
|
@ -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 {
|
||||||
#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 {
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ errout:
|
||||||
* 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)
|
||||||
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 @@ retry:
|
||||||
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 @@ retry:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
/*
|
/*
|
||||||
* 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,
|
||||||
|
|
||||||
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;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче