aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r--kernel/perf_event.c136
1 files changed, 65 insertions, 71 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index f309e8014c78..cb6c0d2af68f 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -417,8 +417,8 @@ event_filter_match(struct perf_event *event)
417 return event->cpu == -1 || event->cpu == smp_processor_id(); 417 return event->cpu == -1 || event->cpu == smp_processor_id();
418} 418}
419 419
420static int 420static void
421__event_sched_out(struct perf_event *event, 421event_sched_out(struct perf_event *event,
422 struct perf_cpu_context *cpuctx, 422 struct perf_cpu_context *cpuctx,
423 struct perf_event_context *ctx) 423 struct perf_event_context *ctx)
424{ 424{
@@ -437,13 +437,14 @@ __event_sched_out(struct perf_event *event,
437 } 437 }
438 438
439 if (event->state != PERF_EVENT_STATE_ACTIVE) 439 if (event->state != PERF_EVENT_STATE_ACTIVE)
440 return 0; 440 return;
441 441
442 event->state = PERF_EVENT_STATE_INACTIVE; 442 event->state = PERF_EVENT_STATE_INACTIVE;
443 if (event->pending_disable) { 443 if (event->pending_disable) {
444 event->pending_disable = 0; 444 event->pending_disable = 0;
445 event->state = PERF_EVENT_STATE_OFF; 445 event->state = PERF_EVENT_STATE_OFF;
446 } 446 }
447 event->tstamp_stopped = ctx->time;
447 event->pmu->del(event, 0); 448 event->pmu->del(event, 0);
448 event->oncpu = -1; 449 event->oncpu = -1;
449 450
@@ -452,19 +453,6 @@ __event_sched_out(struct perf_event *event,
452 ctx->nr_active--; 453 ctx->nr_active--;
453 if (event->attr.exclusive || !cpuctx->active_oncpu) 454 if (event->attr.exclusive || !cpuctx->active_oncpu)
454 cpuctx->exclusive = 0; 455 cpuctx->exclusive = 0;
455 return 1;
456}
457
458static void
459event_sched_out(struct perf_event *event,
460 struct perf_cpu_context *cpuctx,
461 struct perf_event_context *ctx)
462{
463 int ret;
464
465 ret = __event_sched_out(event, cpuctx, ctx);
466 if (ret)
467 event->tstamp_stopped = ctx->time;
468} 456}
469 457
470static void 458static void
@@ -664,7 +652,7 @@ retry:
664} 652}
665 653
666static int 654static int
667__event_sched_in(struct perf_event *event, 655event_sched_in(struct perf_event *event,
668 struct perf_cpu_context *cpuctx, 656 struct perf_cpu_context *cpuctx,
669 struct perf_event_context *ctx) 657 struct perf_event_context *ctx)
670{ 658{
@@ -684,6 +672,10 @@ __event_sched_in(struct perf_event *event,
684 return -EAGAIN; 672 return -EAGAIN;
685 } 673 }
686 674
675 event->tstamp_running += ctx->time - event->tstamp_stopped;
676
677 event->shadow_ctx_time = ctx->time - ctx->timestamp;
678
687 if (!is_software_event(event)) 679 if (!is_software_event(event))
688 cpuctx->active_oncpu++; 680 cpuctx->active_oncpu++;
689 ctx->nr_active++; 681 ctx->nr_active++;
@@ -694,35 +686,6 @@ __event_sched_in(struct perf_event *event,
694 return 0; 686 return 0;
695} 687}
696 688
697static inline int
698event_sched_in(struct perf_event *event,
699 struct perf_cpu_context *cpuctx,
700 struct perf_event_context *ctx)
701{
702 int ret = __event_sched_in(event, cpuctx, ctx);
703 if (ret)
704 return ret;
705 event->tstamp_running += ctx->time - event->tstamp_stopped;
706 return 0;
707}
708
709static void
710group_commit_event_sched_in(struct perf_event *group_event,
711 struct perf_cpu_context *cpuctx,
712 struct perf_event_context *ctx)
713{
714 struct perf_event *event;
715 u64 now = ctx->time;
716
717 group_event->tstamp_running += now - group_event->tstamp_stopped;
718 /*
719 * Schedule in siblings as one group (if any):
720 */
721 list_for_each_entry(event, &group_event->sibling_list, group_entry) {
722 event->tstamp_running += now - event->tstamp_stopped;
723 }
724}
725
726static int 689static int
727group_sched_in(struct perf_event *group_event, 690group_sched_in(struct perf_event *group_event,
728 struct perf_cpu_context *cpuctx, 691 struct perf_cpu_context *cpuctx,
@@ -730,19 +693,15 @@ group_sched_in(struct perf_event *group_event,
730{ 693{
731 struct perf_event *event, *partial_group = NULL; 694 struct perf_event *event, *partial_group = NULL;
732 struct pmu *pmu = group_event->pmu; 695 struct pmu *pmu = group_event->pmu;
696 u64 now = ctx->time;
697 bool simulate = false;
733 698
734 if (group_event->state == PERF_EVENT_STATE_OFF) 699 if (group_event->state == PERF_EVENT_STATE_OFF)
735 return 0; 700 return 0;
736 701
737 pmu->start_txn(pmu); 702 pmu->start_txn(pmu);
738 703
739 /* 704 if (event_sched_in(group_event, cpuctx, ctx)) {
740 * use __event_sched_in() to delay updating tstamp_running
741 * until the transaction is committed. In case of failure
742 * we will keep an unmodified tstamp_running which is a
743 * requirement to get correct timing information
744 */
745 if (__event_sched_in(group_event, cpuctx, ctx)) {
746 pmu->cancel_txn(pmu); 705 pmu->cancel_txn(pmu);
747 return -EAGAIN; 706 return -EAGAIN;
748 } 707 }
@@ -751,31 +710,42 @@ group_sched_in(struct perf_event *group_event,
751 * Schedule in siblings as one group (if any): 710 * Schedule in siblings as one group (if any):
752 */ 711 */
753 list_for_each_entry(event, &group_event->sibling_list, group_entry) { 712 list_for_each_entry(event, &group_event->sibling_list, group_entry) {
754 if (__event_sched_in(event, cpuctx, ctx)) { 713 if (event_sched_in(event, cpuctx, ctx)) {
755 partial_group = event; 714 partial_group = event;
756 goto group_error; 715 goto group_error;
757 } 716 }
758 } 717 }
759 718
760 if (!pmu->commit_txn(pmu)) { 719 if (!pmu->commit_txn(pmu))
761 /* commit tstamp_running */
762 group_commit_event_sched_in(group_event, cpuctx, ctx);
763 return 0; 720 return 0;
764 } 721
765group_error: 722group_error:
766 /* 723 /*
767 * Groups can be scheduled in as one unit only, so undo any 724 * Groups can be scheduled in as one unit only, so undo any
768 * partial group before returning: 725 * partial group before returning:
726 * The events up to the failed event are scheduled out normally,
727 * tstamp_stopped will be updated.
769 * 728 *
770 * use __event_sched_out() to avoid updating tstamp_stopped 729 * The failed events and the remaining siblings need to have
771 * because the event never actually ran 730 * their timings updated as if they had gone thru event_sched_in()
731 * and event_sched_out(). This is required to get consistent timings
732 * across the group. This also takes care of the case where the group
733 * could never be scheduled by ensuring tstamp_stopped is set to mark
734 * the time the event was actually stopped, such that time delta
735 * calculation in update_event_times() is correct.
772 */ 736 */
773 list_for_each_entry(event, &group_event->sibling_list, group_entry) { 737 list_for_each_entry(event, &group_event->sibling_list, group_entry) {
774 if (event == partial_group) 738 if (event == partial_group)
775 break; 739 simulate = true;
776 __event_sched_out(event, cpuctx, ctx); 740
741 if (simulate) {
742 event->tstamp_running += now - event->tstamp_stopped;
743 event->tstamp_stopped = now;
744 } else {
745 event_sched_out(event, cpuctx, ctx);
746 }
777 } 747 }
778 __event_sched_out(group_event, cpuctx, ctx); 748 event_sched_out(group_event, cpuctx, ctx);
779 749
780 pmu->cancel_txn(pmu); 750 pmu->cancel_txn(pmu);
781 751
@@ -3428,7 +3398,8 @@ static u32 perf_event_tid(struct perf_event *event, struct task_struct *p)
3428} 3398}
3429 3399
3430static void perf_output_read_one(struct perf_output_handle *handle, 3400static void perf_output_read_one(struct perf_output_handle *handle,
3431 struct perf_event *event) 3401 struct perf_event *event,
3402 u64 enabled, u64 running)
3432{ 3403{
3433 u64 read_format = event->attr.read_format; 3404 u64 read_format = event->attr.read_format;
3434 u64 values[4]; 3405 u64 values[4];
@@ -3436,11 +3407,11 @@ static void perf_output_read_one(struct perf_output_handle *handle,
3436 3407
3437 values[n++] = perf_event_count(event); 3408 values[n++] = perf_event_count(event);
3438 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { 3409 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
3439 values[n++] = event->total_time_enabled + 3410 values[n++] = enabled +
3440 atomic64_read(&event->child_total_time_enabled); 3411 atomic64_read(&event->child_total_time_enabled);
3441 } 3412 }
3442 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { 3413 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
3443 values[n++] = event->total_time_running + 3414 values[n++] = running +
3444 atomic64_read(&event->child_total_time_running); 3415 atomic64_read(&event->child_total_time_running);
3445 } 3416 }
3446 if (read_format & PERF_FORMAT_ID) 3417 if (read_format & PERF_FORMAT_ID)
@@ -3453,7 +3424,8 @@ static void perf_output_read_one(struct perf_output_handle *handle,
3453 * XXX PERF_FORMAT_GROUP vs inherited events seems difficult. 3424 * XXX PERF_FORMAT_GROUP vs inherited events seems difficult.
3454 */ 3425 */
3455static void perf_output_read_group(struct perf_output_handle *handle, 3426static void perf_output_read_group(struct perf_output_handle *handle,
3456 struct perf_event *event) 3427 struct perf_event *event,
3428 u64 enabled, u64 running)
3457{ 3429{
3458 struct perf_event *leader = event->group_leader, *sub; 3430 struct perf_event *leader = event->group_leader, *sub;
3459 u64 read_format = event->attr.read_format; 3431 u64 read_format = event->attr.read_format;
@@ -3463,10 +3435,10 @@ static void perf_output_read_group(struct perf_output_handle *handle,
3463 values[n++] = 1 + leader->nr_siblings; 3435 values[n++] = 1 + leader->nr_siblings;
3464 3436
3465 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 3437 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
3466 values[n++] = leader->total_time_enabled; 3438 values[n++] = enabled;
3467 3439
3468 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 3440 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
3469 values[n++] = leader->total_time_running; 3441 values[n++] = running;
3470 3442
3471 if (leader != event) 3443 if (leader != event)
3472 leader->pmu->read(leader); 3444 leader->pmu->read(leader);
@@ -3491,13 +3463,35 @@ static void perf_output_read_group(struct perf_output_handle *handle,
3491 } 3463 }
3492} 3464}
3493 3465
3466#define PERF_FORMAT_TOTAL_TIMES (PERF_FORMAT_TOTAL_TIME_ENABLED|\
3467 PERF_FORMAT_TOTAL_TIME_RUNNING)
3468
3494static void perf_output_read(struct perf_output_handle *handle, 3469static void perf_output_read(struct perf_output_handle *handle,
3495 struct perf_event *event) 3470 struct perf_event *event)
3496{ 3471{
3472 u64 enabled = 0, running = 0, now, ctx_time;
3473 u64 read_format = event->attr.read_format;
3474
3475 /*
3476 * compute total_time_enabled, total_time_running
3477 * based on snapshot values taken when the event
3478 * was last scheduled in.
3479 *
3480 * we cannot simply called update_context_time()
3481 * because of locking issue as we are called in
3482 * NMI context
3483 */
3484 if (read_format & PERF_FORMAT_TOTAL_TIMES) {
3485 now = perf_clock();
3486 ctx_time = event->shadow_ctx_time + now;
3487 enabled = ctx_time - event->tstamp_enabled;
3488 running = ctx_time - event->tstamp_running;
3489 }
3490
3497 if (event->attr.read_format & PERF_FORMAT_GROUP) 3491 if (event->attr.read_format & PERF_FORMAT_GROUP)
3498 perf_output_read_group(handle, event); 3492 perf_output_read_group(handle, event, enabled, running);
3499 else 3493 else
3500 perf_output_read_one(handle, event); 3494 perf_output_read_one(handle, event, enabled, running);
3501} 3495}
3502 3496
3503void perf_output_sample(struct perf_output_handle *handle, 3497void perf_output_sample(struct perf_output_handle *handle,