diff options
Diffstat (limited to 'kernel/events/core.c')
-rw-r--r-- | kernel/events/core.c | 47 |
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 | ||
2039 | static void task_ctx_sched_out(struct perf_event_context *ctx); | 2039 | static void task_ctx_sched_out(struct perf_cpu_context *cpuctx, |
2040 | struct perf_event_context *ctx); | ||
2040 | static void | 2041 | static void |
2041 | ctx_sched_in(struct perf_event_context *ctx, | 2042 | ctx_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 | ||
2071 | static 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 | ||
2632 | static void task_ctx_sched_out(struct perf_event_context *ctx) | 2644 | static 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, | |||
3096 | static void perf_event_enable_on_exec(int ctxn) | 3107 | static 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); | ||
3127 | out: | 3134 | out: |
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 | /* |