aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_counter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/perf_counter.c')
-rw-r--r--kernel/perf_counter.c43
1 files changed, 30 insertions, 13 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index f274e1959885..06bf6a4f2608 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -469,7 +469,8 @@ static void update_counter_times(struct perf_counter *counter)
469 struct perf_counter_context *ctx = counter->ctx; 469 struct perf_counter_context *ctx = counter->ctx;
470 u64 run_end; 470 u64 run_end;
471 471
472 if (counter->state < PERF_COUNTER_STATE_INACTIVE) 472 if (counter->state < PERF_COUNTER_STATE_INACTIVE ||
473 counter->group_leader->state < PERF_COUNTER_STATE_INACTIVE)
473 return; 474 return;
474 475
475 counter->total_time_enabled = ctx->time - counter->tstamp_enabled; 476 counter->total_time_enabled = ctx->time - counter->tstamp_enabled;
@@ -518,7 +519,7 @@ static void __perf_counter_disable(void *info)
518 */ 519 */
519 if (counter->state >= PERF_COUNTER_STATE_INACTIVE) { 520 if (counter->state >= PERF_COUNTER_STATE_INACTIVE) {
520 update_context_time(ctx); 521 update_context_time(ctx);
521 update_counter_times(counter); 522 update_group_times(counter);
522 if (counter == counter->group_leader) 523 if (counter == counter->group_leader)
523 group_sched_out(counter, cpuctx, ctx); 524 group_sched_out(counter, cpuctx, ctx);
524 else 525 else
@@ -573,7 +574,7 @@ static void perf_counter_disable(struct perf_counter *counter)
573 * in, so we can change the state safely. 574 * in, so we can change the state safely.
574 */ 575 */
575 if (counter->state == PERF_COUNTER_STATE_INACTIVE) { 576 if (counter->state == PERF_COUNTER_STATE_INACTIVE) {
576 update_counter_times(counter); 577 update_group_times(counter);
577 counter->state = PERF_COUNTER_STATE_OFF; 578 counter->state = PERF_COUNTER_STATE_OFF;
578 } 579 }
579 580
@@ -851,6 +852,27 @@ retry:
851} 852}
852 853
853/* 854/*
855 * Put a counter into inactive state and update time fields.
856 * Enabling the leader of a group effectively enables all
857 * the group members that aren't explicitly disabled, so we
858 * have to update their ->tstamp_enabled also.
859 * Note: this works for group members as well as group leaders
860 * since the non-leader members' sibling_lists will be empty.
861 */
862static void __perf_counter_mark_enabled(struct perf_counter *counter,
863 struct perf_counter_context *ctx)
864{
865 struct perf_counter *sub;
866
867 counter->state = PERF_COUNTER_STATE_INACTIVE;
868 counter->tstamp_enabled = ctx->time - counter->total_time_enabled;
869 list_for_each_entry(sub, &counter->sibling_list, list_entry)
870 if (sub->state >= PERF_COUNTER_STATE_INACTIVE)
871 sub->tstamp_enabled =
872 ctx->time - sub->total_time_enabled;
873}
874
875/*
854 * Cross CPU call to enable a performance counter 876 * Cross CPU call to enable a performance counter
855 */ 877 */
856static void __perf_counter_enable(void *info) 878static void __perf_counter_enable(void *info)
@@ -877,8 +899,7 @@ static void __perf_counter_enable(void *info)
877 899
878 if (counter->state >= PERF_COUNTER_STATE_INACTIVE) 900 if (counter->state >= PERF_COUNTER_STATE_INACTIVE)
879 goto unlock; 901 goto unlock;
880 counter->state = PERF_COUNTER_STATE_INACTIVE; 902 __perf_counter_mark_enabled(counter, ctx);
881 counter->tstamp_enabled = ctx->time - counter->total_time_enabled;
882 903
883 /* 904 /*
884 * If the counter is in a group and isn't the group leader, 905 * If the counter is in a group and isn't the group leader,
@@ -971,11 +992,9 @@ static void perf_counter_enable(struct perf_counter *counter)
971 * Since we have the lock this context can't be scheduled 992 * Since we have the lock this context can't be scheduled
972 * in, so we can change the state safely. 993 * in, so we can change the state safely.
973 */ 994 */
974 if (counter->state == PERF_COUNTER_STATE_OFF) { 995 if (counter->state == PERF_COUNTER_STATE_OFF)
975 counter->state = PERF_COUNTER_STATE_INACTIVE; 996 __perf_counter_mark_enabled(counter, ctx);
976 counter->tstamp_enabled = 997
977 ctx->time - counter->total_time_enabled;
978 }
979 out: 998 out:
980 spin_unlock_irq(&ctx->lock); 999 spin_unlock_irq(&ctx->lock);
981} 1000}
@@ -1479,9 +1498,7 @@ static void perf_counter_enable_on_exec(struct task_struct *task)
1479 counter->attr.enable_on_exec = 0; 1498 counter->attr.enable_on_exec = 0;
1480 if (counter->state >= PERF_COUNTER_STATE_INACTIVE) 1499 if (counter->state >= PERF_COUNTER_STATE_INACTIVE)
1481 continue; 1500 continue;
1482 counter->state = PERF_COUNTER_STATE_INACTIVE; 1501 __perf_counter_mark_enabled(counter, ctx);
1483 counter->tstamp_enabled =
1484 ctx->time - counter->total_time_enabled;
1485 enabled = 1; 1502 enabled = 1;
1486 } 1503 }
1487 1504