diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/perf_event.c | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 39afdb07d758..517d827f4982 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -691,6 +691,8 @@ group_sched_in(struct perf_event *group_event, | |||
691 | { | 691 | { |
692 | struct perf_event *event, *partial_group = NULL; | 692 | struct perf_event *event, *partial_group = NULL; |
693 | struct pmu *pmu = group_event->pmu; | 693 | struct pmu *pmu = group_event->pmu; |
694 | u64 now = ctx->time; | ||
695 | bool simulate = false; | ||
694 | 696 | ||
695 | if (group_event->state == PERF_EVENT_STATE_OFF) | 697 | if (group_event->state == PERF_EVENT_STATE_OFF) |
696 | return 0; | 698 | return 0; |
@@ -719,11 +721,27 @@ group_error: | |||
719 | /* | 721 | /* |
720 | * Groups can be scheduled in as one unit only, so undo any | 722 | * Groups can be scheduled in as one unit only, so undo any |
721 | * partial group before returning: | 723 | * partial group before returning: |
724 | * The events up to the failed event are scheduled out normally, | ||
725 | * tstamp_stopped will be updated. | ||
726 | * | ||
727 | * The failed events and the remaining siblings need to have | ||
728 | * their timings updated as if they had gone thru event_sched_in() | ||
729 | * and event_sched_out(). This is required to get consistent timings | ||
730 | * across the group. This also takes care of the case where the group | ||
731 | * could never be scheduled by ensuring tstamp_stopped is set to mark | ||
732 | * the time the event was actually stopped, such that time delta | ||
733 | * calculation in update_event_times() is correct. | ||
722 | */ | 734 | */ |
723 | list_for_each_entry(event, &group_event->sibling_list, group_entry) { | 735 | list_for_each_entry(event, &group_event->sibling_list, group_entry) { |
724 | if (event == partial_group) | 736 | if (event == partial_group) |
725 | break; | 737 | simulate = true; |
726 | event_sched_out(event, cpuctx, ctx); | 738 | |
739 | if (simulate) { | ||
740 | event->tstamp_running += now - event->tstamp_stopped; | ||
741 | event->tstamp_stopped = now; | ||
742 | } else { | ||
743 | event_sched_out(event, cpuctx, ctx); | ||
744 | } | ||
727 | } | 745 | } |
728 | event_sched_out(group_event, cpuctx, ctx); | 746 | event_sched_out(group_event, cpuctx, ctx); |
729 | 747 | ||