diff options
| -rw-r--r-- | kernel/events/core.c | 42 |
1 files changed, 30 insertions, 12 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index de14b67a3b0b..75bde93eb76f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
| @@ -314,6 +314,7 @@ again: | |||
| 314 | enum event_type_t { | 314 | enum event_type_t { |
| 315 | EVENT_FLEXIBLE = 0x1, | 315 | EVENT_FLEXIBLE = 0x1, |
| 316 | EVENT_PINNED = 0x2, | 316 | EVENT_PINNED = 0x2, |
| 317 | EVENT_TIME = 0x4, | ||
| 317 | EVENT_ALL = EVENT_FLEXIBLE | EVENT_PINNED, | 318 | EVENT_ALL = EVENT_FLEXIBLE | EVENT_PINNED, |
| 318 | }; | 319 | }; |
| 319 | 320 | ||
| @@ -1294,16 +1295,18 @@ static u64 perf_event_time(struct perf_event *event) | |||
| 1294 | 1295 | ||
| 1295 | /* | 1296 | /* |
| 1296 | * Update the total_time_enabled and total_time_running fields for a event. | 1297 | * Update the total_time_enabled and total_time_running fields for a event. |
| 1297 | * The caller of this function needs to hold the ctx->lock. | ||
| 1298 | */ | 1298 | */ |
| 1299 | static void update_event_times(struct perf_event *event) | 1299 | static void update_event_times(struct perf_event *event) |
| 1300 | { | 1300 | { |
| 1301 | struct perf_event_context *ctx = event->ctx; | 1301 | struct perf_event_context *ctx = event->ctx; |
| 1302 | u64 run_end; | 1302 | u64 run_end; |
| 1303 | 1303 | ||
| 1304 | lockdep_assert_held(&ctx->lock); | ||
| 1305 | |||
| 1304 | if (event->state < PERF_EVENT_STATE_INACTIVE || | 1306 | if (event->state < PERF_EVENT_STATE_INACTIVE || |
| 1305 | event->group_leader->state < PERF_EVENT_STATE_INACTIVE) | 1307 | event->group_leader->state < PERF_EVENT_STATE_INACTIVE) |
| 1306 | return; | 1308 | return; |
| 1309 | |||
| 1307 | /* | 1310 | /* |
| 1308 | * in cgroup mode, time_enabled represents | 1311 | * in cgroup mode, time_enabled represents |
| 1309 | * the time the event was enabled AND active | 1312 | * the time the event was enabled AND active |
| @@ -2349,24 +2352,33 @@ static void ctx_sched_out(struct perf_event_context *ctx, | |||
| 2349 | } | 2352 | } |
| 2350 | 2353 | ||
| 2351 | ctx->is_active &= ~event_type; | 2354 | ctx->is_active &= ~event_type; |
| 2355 | if (!(ctx->is_active & EVENT_ALL)) | ||
| 2356 | ctx->is_active = 0; | ||
| 2357 | |||
| 2352 | if (ctx->task) { | 2358 | if (ctx->task) { |
| 2353 | WARN_ON_ONCE(cpuctx->task_ctx != ctx); | 2359 | WARN_ON_ONCE(cpuctx->task_ctx != ctx); |
| 2354 | if (!ctx->is_active) | 2360 | if (!ctx->is_active) |
| 2355 | cpuctx->task_ctx = NULL; | 2361 | cpuctx->task_ctx = NULL; |
| 2356 | } | 2362 | } |
| 2357 | 2363 | ||
| 2358 | update_context_time(ctx); | 2364 | is_active ^= ctx->is_active; /* changed bits */ |
| 2359 | update_cgrp_time_from_cpuctx(cpuctx); | 2365 | |
| 2360 | if (!ctx->nr_active) | 2366 | if (is_active & EVENT_TIME) { |
| 2367 | /* update (and stop) ctx time */ | ||
| 2368 | update_context_time(ctx); | ||
| 2369 | update_cgrp_time_from_cpuctx(cpuctx); | ||
| 2370 | } | ||
| 2371 | |||
| 2372 | if (!ctx->nr_active || !(is_active & EVENT_ALL)) | ||
| 2361 | return; | 2373 | return; |
| 2362 | 2374 | ||
| 2363 | perf_pmu_disable(ctx->pmu); | 2375 | perf_pmu_disable(ctx->pmu); |
| 2364 | if ((is_active & EVENT_PINNED) && (event_type & EVENT_PINNED)) { | 2376 | if (is_active & EVENT_PINNED) { |
| 2365 | list_for_each_entry(event, &ctx->pinned_groups, group_entry) | 2377 | list_for_each_entry(event, &ctx->pinned_groups, group_entry) |
| 2366 | group_sched_out(event, cpuctx, ctx); | 2378 | group_sched_out(event, cpuctx, ctx); |
| 2367 | } | 2379 | } |
| 2368 | 2380 | ||
| 2369 | if ((is_active & EVENT_FLEXIBLE) && (event_type & EVENT_FLEXIBLE)) { | 2381 | if (is_active & EVENT_FLEXIBLE) { |
| 2370 | list_for_each_entry(event, &ctx->flexible_groups, group_entry) | 2382 | list_for_each_entry(event, &ctx->flexible_groups, group_entry) |
| 2371 | group_sched_out(event, cpuctx, ctx); | 2383 | group_sched_out(event, cpuctx, ctx); |
| 2372 | } | 2384 | } |
| @@ -2740,7 +2752,7 @@ ctx_sched_in(struct perf_event_context *ctx, | |||
| 2740 | if (likely(!ctx->nr_events)) | 2752 | if (likely(!ctx->nr_events)) |
| 2741 | return; | 2753 | return; |
| 2742 | 2754 | ||
| 2743 | ctx->is_active |= event_type; | 2755 | ctx->is_active |= (event_type | EVENT_TIME); |
| 2744 | if (ctx->task) { | 2756 | if (ctx->task) { |
| 2745 | if (!is_active) | 2757 | if (!is_active) |
| 2746 | cpuctx->task_ctx = ctx; | 2758 | cpuctx->task_ctx = ctx; |
| @@ -2748,18 +2760,24 @@ ctx_sched_in(struct perf_event_context *ctx, | |||
| 2748 | WARN_ON_ONCE(cpuctx->task_ctx != ctx); | 2760 | WARN_ON_ONCE(cpuctx->task_ctx != ctx); |
| 2749 | } | 2761 | } |
| 2750 | 2762 | ||
| 2751 | now = perf_clock(); | 2763 | is_active ^= ctx->is_active; /* changed bits */ |
| 2752 | ctx->timestamp = now; | 2764 | |
| 2753 | perf_cgroup_set_timestamp(task, ctx); | 2765 | if (is_active & EVENT_TIME) { |
| 2766 | /* start ctx time */ | ||
| 2767 | now = perf_clock(); | ||
| 2768 | ctx->timestamp = now; | ||
| 2769 | perf_cgroup_set_timestamp(task, ctx); | ||
| 2770 | } | ||
| 2771 | |||
| 2754 | /* | 2772 | /* |
| 2755 | * First go through the list and put on any pinned groups | 2773 | * First go through the list and put on any pinned groups |
| 2756 | * in order to give them the best chance of going on. | 2774 | * in order to give them the best chance of going on. |
| 2757 | */ | 2775 | */ |
| 2758 | if (!(is_active & EVENT_PINNED) && (event_type & EVENT_PINNED)) | 2776 | if (is_active & EVENT_PINNED) |
| 2759 | ctx_pinned_sched_in(ctx, cpuctx); | 2777 | ctx_pinned_sched_in(ctx, cpuctx); |
| 2760 | 2778 | ||
| 2761 | /* Then walk through the lower prio flexible groups */ | 2779 | /* Then walk through the lower prio flexible groups */ |
| 2762 | if (!(is_active & EVENT_FLEXIBLE) && (event_type & EVENT_FLEXIBLE)) | 2780 | if (is_active & EVENT_FLEXIBLE) |
| 2763 | ctx_flexible_sched_in(ctx, cpuctx); | 2781 | ctx_flexible_sched_in(ctx, cpuctx); |
| 2764 | } | 2782 | } |
| 2765 | 2783 | ||
