diff options
| -rw-r--r-- | arch/x86/include/asm/perf_event_p4.h | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_p4.c | 11 | ||||
| -rw-r--r-- | kernel/perf_event.c | 19 |
3 files changed, 24 insertions, 7 deletions
diff --git a/arch/x86/include/asm/perf_event_p4.h b/arch/x86/include/asm/perf_event_p4.h index e2f6a99f14a..cc29086e30c 100644 --- a/arch/x86/include/asm/perf_event_p4.h +++ b/arch/x86/include/asm/perf_event_p4.h | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | 22 | ||
| 23 | #define ARCH_P4_CNTRVAL_BITS (40) | 23 | #define ARCH_P4_CNTRVAL_BITS (40) |
| 24 | #define ARCH_P4_CNTRVAL_MASK ((1ULL << ARCH_P4_CNTRVAL_BITS) - 1) | 24 | #define ARCH_P4_CNTRVAL_MASK ((1ULL << ARCH_P4_CNTRVAL_BITS) - 1) |
| 25 | #define ARCH_P4_UNFLAGGED_BIT ((1ULL) << (ARCH_P4_CNTRVAL_BITS - 1)) | ||
| 25 | 26 | ||
| 26 | #define P4_ESCR_EVENT_MASK 0x7e000000U | 27 | #define P4_ESCR_EVENT_MASK 0x7e000000U |
| 27 | #define P4_ESCR_EVENT_SHIFT 25 | 28 | #define P4_ESCR_EVENT_SHIFT 25 |
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index f7a0993c1e7..ff751a9f182 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c | |||
| @@ -770,9 +770,14 @@ static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc) | |||
| 770 | return 1; | 770 | return 1; |
| 771 | } | 771 | } |
| 772 | 772 | ||
| 773 | /* it might be unflagged overflow */ | 773 | /* |
| 774 | rdmsrl(hwc->event_base + hwc->idx, v); | 774 | * In some circumstances the overflow might issue an NMI but did |
| 775 | if (!(v & ARCH_P4_CNTRVAL_MASK)) | 775 | * not set P4_CCCR_OVF bit. Because a counter holds a negative value |
| 776 | * we simply check for high bit being set, if it's cleared it means | ||
| 777 | * the counter has reached zero value and continued counting before | ||
| 778 | * real NMI signal was received: | ||
| 779 | */ | ||
| 780 | if (!(v & ARCH_P4_UNFLAGGED_BIT)) | ||
| 776 | return 1; | 781 | return 1; |
| 777 | 782 | ||
| 778 | return 0; | 783 | return 0; |
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 999835b6112..656222fcf76 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
| @@ -782,6 +782,10 @@ retry: | |||
| 782 | raw_spin_unlock_irq(&ctx->lock); | 782 | raw_spin_unlock_irq(&ctx->lock); |
| 783 | } | 783 | } |
| 784 | 784 | ||
| 785 | #define MAX_INTERRUPTS (~0ULL) | ||
| 786 | |||
| 787 | static void perf_log_throttle(struct perf_event *event, int enable); | ||
| 788 | |||
| 785 | static int | 789 | static int |
| 786 | event_sched_in(struct perf_event *event, | 790 | event_sched_in(struct perf_event *event, |
| 787 | struct perf_cpu_context *cpuctx, | 791 | struct perf_cpu_context *cpuctx, |
| @@ -794,6 +798,17 @@ event_sched_in(struct perf_event *event, | |||
| 794 | 798 | ||
| 795 | event->state = PERF_EVENT_STATE_ACTIVE; | 799 | event->state = PERF_EVENT_STATE_ACTIVE; |
| 796 | event->oncpu = smp_processor_id(); | 800 | event->oncpu = smp_processor_id(); |
| 801 | |||
| 802 | /* | ||
| 803 | * Unthrottle events, since we scheduled we might have missed several | ||
| 804 | * ticks already, also for a heavily scheduling task there is little | ||
| 805 | * guarantee it'll get a tick in a timely manner. | ||
| 806 | */ | ||
| 807 | if (unlikely(event->hw.interrupts == MAX_INTERRUPTS)) { | ||
| 808 | perf_log_throttle(event, 1); | ||
| 809 | event->hw.interrupts = 0; | ||
| 810 | } | ||
| 811 | |||
| 797 | /* | 812 | /* |
| 798 | * The new state must be visible before we turn it on in the hardware: | 813 | * The new state must be visible before we turn it on in the hardware: |
| 799 | */ | 814 | */ |
| @@ -1596,10 +1611,6 @@ void __perf_event_task_sched_in(struct task_struct *task) | |||
| 1596 | } | 1611 | } |
| 1597 | } | 1612 | } |
| 1598 | 1613 | ||
| 1599 | #define MAX_INTERRUPTS (~0ULL) | ||
| 1600 | |||
| 1601 | static void perf_log_throttle(struct perf_event *event, int enable); | ||
| 1602 | |||
| 1603 | static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count) | 1614 | static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count) |
| 1604 | { | 1615 | { |
| 1605 | u64 frequency = event->attr.sample_freq; | 1616 | u64 frequency = event->attr.sample_freq; |
