aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/events/core.c')
-rw-r--r--kernel/events/core.c47
1 files changed, 27 insertions, 20 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 751538ce19a7..0679e73f5f63 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2036,7 +2036,8 @@ static void add_event_to_ctx(struct perf_event *event,
2036 event->tstamp_stopped = tstamp; 2036 event->tstamp_stopped = tstamp;
2037} 2037}
2038 2038
2039static void task_ctx_sched_out(struct perf_event_context *ctx); 2039static void task_ctx_sched_out(struct perf_cpu_context *cpuctx,
2040 struct perf_event_context *ctx);
2040static void 2041static void
2041ctx_sched_in(struct perf_event_context *ctx, 2042ctx_sched_in(struct perf_event_context *ctx,
2042 struct perf_cpu_context *cpuctx, 2043 struct perf_cpu_context *cpuctx,
@@ -2067,6 +2068,17 @@ static void ___perf_install_in_context(void *info)
2067 add_event_to_ctx(event, ctx); 2068 add_event_to_ctx(event, ctx);
2068} 2069}
2069 2070
2071static void ctx_resched(struct perf_cpu_context *cpuctx,
2072 struct perf_event_context *task_ctx)
2073{
2074 perf_pmu_disable(cpuctx->ctx.pmu);
2075 if (task_ctx)
2076 task_ctx_sched_out(cpuctx, task_ctx);
2077 cpu_ctx_sched_out(cpuctx, EVENT_ALL);
2078 perf_event_sched_in(cpuctx, task_ctx, current);
2079 perf_pmu_enable(cpuctx->ctx.pmu);
2080}
2081
2070/* 2082/*
2071 * Cross CPU call to install and enable a performance event 2083 * Cross CPU call to install and enable a performance event
2072 * 2084 *
@@ -2087,7 +2099,7 @@ static int __perf_install_in_context(void *info)
2087 * If there was an active task_ctx schedule it out. 2099 * If there was an active task_ctx schedule it out.
2088 */ 2100 */
2089 if (task_ctx) 2101 if (task_ctx)
2090 task_ctx_sched_out(task_ctx); 2102 task_ctx_sched_out(cpuctx, task_ctx);
2091 2103
2092 /* 2104 /*
2093 * If the context we're installing events in is not the 2105 * If the context we're installing events in is not the
@@ -2629,10 +2641,9 @@ void __perf_event_task_sched_out(struct task_struct *task,
2629 perf_cgroup_sched_out(task, next); 2641 perf_cgroup_sched_out(task, next);
2630} 2642}
2631 2643
2632static void task_ctx_sched_out(struct perf_event_context *ctx) 2644static void task_ctx_sched_out(struct perf_cpu_context *cpuctx,
2645 struct perf_event_context *ctx)
2633{ 2646{
2634 struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
2635
2636 if (!cpuctx->task_ctx) 2647 if (!cpuctx->task_ctx)
2637 return; 2648 return;
2638 2649
@@ -3096,34 +3107,30 @@ static int event_enable_on_exec(struct perf_event *event,
3096static void perf_event_enable_on_exec(int ctxn) 3107static void perf_event_enable_on_exec(int ctxn)
3097{ 3108{
3098 struct perf_event_context *ctx, *clone_ctx = NULL; 3109 struct perf_event_context *ctx, *clone_ctx = NULL;
3110 struct perf_cpu_context *cpuctx;
3099 struct perf_event *event; 3111 struct perf_event *event;
3100 unsigned long flags; 3112 unsigned long flags;
3101 int enabled = 0; 3113 int enabled = 0;
3102 int ret;
3103 3114
3104 local_irq_save(flags); 3115 local_irq_save(flags);
3105 ctx = current->perf_event_ctxp[ctxn]; 3116 ctx = current->perf_event_ctxp[ctxn];
3106 if (!ctx || !ctx->nr_events) 3117 if (!ctx || !ctx->nr_events)
3107 goto out; 3118 goto out;
3108 3119
3109 raw_spin_lock(&ctx->lock); 3120 cpuctx = __get_cpu_context(ctx);
3110 task_ctx_sched_out(ctx); 3121 perf_ctx_lock(cpuctx, ctx);
3111 3122 list_for_each_entry(event, &ctx->event_list, event_entry)
3112 list_for_each_entry(event, &ctx->event_list, event_entry) { 3123 enabled |= event_enable_on_exec(event, ctx);
3113 ret = event_enable_on_exec(event, ctx);
3114 if (ret)
3115 enabled = 1;
3116 }
3117 3124
3118 /* 3125 /*
3119 * Unclone this context if we enabled any event. 3126 * Unclone and reschedule this context if we enabled any event.
3120 */ 3127 */
3121 if (enabled) 3128 if (enabled) {
3122 clone_ctx = unclone_ctx(ctx); 3129 clone_ctx = unclone_ctx(ctx);
3130 ctx_resched(cpuctx, ctx);
3131 }
3132 perf_ctx_unlock(cpuctx, ctx);
3123 3133
3124 raw_spin_unlock(&ctx->lock);
3125
3126 perf_event_context_sched_in(ctx, ctx->task);
3127out: 3134out:
3128 local_irq_restore(flags); 3135 local_irq_restore(flags);
3129 3136
@@ -8737,7 +8744,7 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
8737 * incremented the context's refcount before we do put_ctx below. 8744 * incremented the context's refcount before we do put_ctx below.
8738 */ 8745 */
8739 raw_spin_lock(&child_ctx->lock); 8746 raw_spin_lock(&child_ctx->lock);
8740 task_ctx_sched_out(child_ctx); 8747 task_ctx_sched_out(__get_cpu_context(child_ctx), child_ctx);
8741 child->perf_event_ctxp[ctxn] = NULL; 8748 child->perf_event_ctxp[ctxn] = NULL;
8742 8749
8743 /* 8750 /*