diff options
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index c8f5c088cad1..24e390e40f2e 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c | |||
| @@ -816,6 +816,32 @@ static int intel_pmu_hw_config(struct perf_event *event) | |||
| 816 | if (ret) | 816 | if (ret) |
| 817 | return ret; | 817 | return ret; |
| 818 | 818 | ||
| 819 | if (event->attr.precise_ip && | ||
| 820 | (event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) { | ||
| 821 | /* | ||
| 822 | * Use an alternative encoding for CPU_CLK_UNHALTED.THREAD_P | ||
| 823 | * (0x003c) so that we can use it with PEBS. | ||
| 824 | * | ||
| 825 | * The regular CPU_CLK_UNHALTED.THREAD_P event (0x003c) isn't | ||
| 826 | * PEBS capable. However we can use INST_RETIRED.ANY_P | ||
| 827 | * (0x00c0), which is a PEBS capable event, to get the same | ||
| 828 | * count. | ||
| 829 | * | ||
| 830 | * INST_RETIRED.ANY_P counts the number of cycles that retires | ||
| 831 | * CNTMASK instructions. By setting CNTMASK to a value (16) | ||
| 832 | * larger than the maximum number of instructions that can be | ||
| 833 | * retired per cycle (4) and then inverting the condition, we | ||
| 834 | * count all cycles that retire 16 or less instructions, which | ||
| 835 | * is every cycle. | ||
| 836 | * | ||
| 837 | * Thereby we gain a PEBS capable cycle counter. | ||
| 838 | */ | ||
| 839 | u64 alt_config = 0x108000c0; /* INST_RETIRED.TOTAL_CYCLES */ | ||
| 840 | |||
| 841 | alt_config |= (event->hw.config & ~X86_RAW_EVENT_MASK); | ||
| 842 | event->hw.config = alt_config; | ||
| 843 | } | ||
| 844 | |||
| 819 | if (event->attr.type != PERF_TYPE_RAW) | 845 | if (event->attr.type != PERF_TYPE_RAW) |
| 820 | return 0; | 846 | return 0; |
| 821 | 847 | ||
