mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
perf_counter: Start counting time enabled when group leader gets enabled
Currently, if a group is created where the group leader is initially disabled but a non-leader member is initially enabled, and then the leader is subsequently enabled some time later, the time_enabled for the non-leader member will reflect the whole time since it was created, not just the time since the leader was enabled. This is incorrect, because all of the members are effectively disabled while the leader is disabled, since none of the members can go on the PMU if the leader can't. Thus we have to update the ->tstamp_enabled for all the enabled group members when a group leader is enabled, so that the time_enabled computation only counts the time since the leader was enabled. Similarly, when disabling a group leader we have to update the time_enabled and time_running for all of the group members. Also, in update_counter_times, we have to treat a counter whose group leader is disabled as being disabled. Reported-by: Stephane Eranian <eranian@googlemail.com> Signed-off-by: Paul Mackerras <paulus@samba.org> Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: <stable@kernel.org> LKML-Reference: <19091.29664.342227.445006@drongo.ozlabs.ibm.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
96d6e48bc6
commit
fa289beca9
1 changed files with 30 additions and 13 deletions
|
@ -469,7 +469,8 @@ static void update_counter_times(struct perf_counter *counter)
|
||||||
struct perf_counter_context *ctx = counter->ctx;
|
struct perf_counter_context *ctx = counter->ctx;
|
||||||
u64 run_end;
|
u64 run_end;
|
||||||
|
|
||||||
if (counter->state < PERF_COUNTER_STATE_INACTIVE)
|
if (counter->state < PERF_COUNTER_STATE_INACTIVE ||
|
||||||
|
counter->group_leader->state < PERF_COUNTER_STATE_INACTIVE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
counter->total_time_enabled = ctx->time - counter->tstamp_enabled;
|
counter->total_time_enabled = ctx->time - counter->tstamp_enabled;
|
||||||
|
@ -518,7 +519,7 @@ static void __perf_counter_disable(void *info)
|
||||||
*/
|
*/
|
||||||
if (counter->state >= PERF_COUNTER_STATE_INACTIVE) {
|
if (counter->state >= PERF_COUNTER_STATE_INACTIVE) {
|
||||||
update_context_time(ctx);
|
update_context_time(ctx);
|
||||||
update_counter_times(counter);
|
update_group_times(counter);
|
||||||
if (counter == counter->group_leader)
|
if (counter == counter->group_leader)
|
||||||
group_sched_out(counter, cpuctx, ctx);
|
group_sched_out(counter, cpuctx, ctx);
|
||||||
else
|
else
|
||||||
|
@ -573,7 +574,7 @@ static void perf_counter_disable(struct perf_counter *counter)
|
||||||
* in, so we can change the state safely.
|
* in, so we can change the state safely.
|
||||||
*/
|
*/
|
||||||
if (counter->state == PERF_COUNTER_STATE_INACTIVE) {
|
if (counter->state == PERF_COUNTER_STATE_INACTIVE) {
|
||||||
update_counter_times(counter);
|
update_group_times(counter);
|
||||||
counter->state = PERF_COUNTER_STATE_OFF;
|
counter->state = PERF_COUNTER_STATE_OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,6 +851,27 @@ retry:
|
||||||
spin_unlock_irq(&ctx->lock);
|
spin_unlock_irq(&ctx->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Put a counter into inactive state and update time fields.
|
||||||
|
* Enabling the leader of a group effectively enables all
|
||||||
|
* the group members that aren't explicitly disabled, so we
|
||||||
|
* have to update their ->tstamp_enabled also.
|
||||||
|
* Note: this works for group members as well as group leaders
|
||||||
|
* since the non-leader members' sibling_lists will be empty.
|
||||||
|
*/
|
||||||
|
static void __perf_counter_mark_enabled(struct perf_counter *counter,
|
||||||
|
struct perf_counter_context *ctx)
|
||||||
|
{
|
||||||
|
struct perf_counter *sub;
|
||||||
|
|
||||||
|
counter->state = PERF_COUNTER_STATE_INACTIVE;
|
||||||
|
counter->tstamp_enabled = ctx->time - counter->total_time_enabled;
|
||||||
|
list_for_each_entry(sub, &counter->sibling_list, list_entry)
|
||||||
|
if (sub->state >= PERF_COUNTER_STATE_INACTIVE)
|
||||||
|
sub->tstamp_enabled =
|
||||||
|
ctx->time - sub->total_time_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cross CPU call to enable a performance counter
|
* Cross CPU call to enable a performance counter
|
||||||
*/
|
*/
|
||||||
|
@ -877,8 +899,7 @@ static void __perf_counter_enable(void *info)
|
||||||
|
|
||||||
if (counter->state >= PERF_COUNTER_STATE_INACTIVE)
|
if (counter->state >= PERF_COUNTER_STATE_INACTIVE)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
counter->state = PERF_COUNTER_STATE_INACTIVE;
|
__perf_counter_mark_enabled(counter, ctx);
|
||||||
counter->tstamp_enabled = ctx->time - counter->total_time_enabled;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the counter is in a group and isn't the group leader,
|
* 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)
|
||||||
* Since we have the lock this context can't be scheduled
|
* Since we have the lock this context can't be scheduled
|
||||||
* in, so we can change the state safely.
|
* in, so we can change the state safely.
|
||||||
*/
|
*/
|
||||||
if (counter->state == PERF_COUNTER_STATE_OFF) {
|
if (counter->state == PERF_COUNTER_STATE_OFF)
|
||||||
counter->state = PERF_COUNTER_STATE_INACTIVE;
|
__perf_counter_mark_enabled(counter, ctx);
|
||||||
counter->tstamp_enabled =
|
|
||||||
ctx->time - counter->total_time_enabled;
|
|
||||||
}
|
|
||||||
out:
|
out:
|
||||||
spin_unlock_irq(&ctx->lock);
|
spin_unlock_irq(&ctx->lock);
|
||||||
}
|
}
|
||||||
|
@ -1479,9 +1498,7 @@ static void perf_counter_enable_on_exec(struct task_struct *task)
|
||||||
counter->attr.enable_on_exec = 0;
|
counter->attr.enable_on_exec = 0;
|
||||||
if (counter->state >= PERF_COUNTER_STATE_INACTIVE)
|
if (counter->state >= PERF_COUNTER_STATE_INACTIVE)
|
||||||
continue;
|
continue;
|
||||||
counter->state = PERF_COUNTER_STATE_INACTIVE;
|
__perf_counter_mark_enabled(counter, ctx);
|
||||||
counter->tstamp_enabled =
|
|
||||||
ctx->time - counter->total_time_enabled;
|
|
||||||
enabled = 1;
|
enabled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue