aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2019-08-06 04:46:01 -0400
committerPeter Zijlstra <peterz@infradead.org>2019-08-28 05:29:39 -0400
commit42880f726c66f13ae1d9ac9ce4c43abe64ecac84 (patch)
tree24a24d94033bc9c19e1e9356467d04b47f8e668e
parentab43762ef010967e4ccd53627f70a2eecbeafefb (diff)
perf/x86/intel: Support PEBS output to PT
If PEBS declares ability to output its data to Intel PT stream, use the aux_output attribute bit to enable PEBS data output to PT. This requires a PT event to be present and scheduled in the same context. Unlike the DS area, the kernel does not extract PEBS records from the PT stream to generate corresponding records in the perf stream, because that would require real time in-kernel PT decoding, which is not feasible. The PMI, however, can still be used. The output setting is per-CPU, so all PEBS events must be either writing to PT or to the DS area, therefore, in case of conflict, the conflicting event will fail to schedule, allowing the rotation logic to alternate between the PEBS->PT and PEBS->DS events. Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: kan.liang@linux.intel.com Link: https://lkml.kernel.org/r/20190806084606.4021-3-alexander.shishkin@linux.intel.com
-rw-r--r--arch/x86/events/core.c34
-rw-r--r--arch/x86/events/intel/core.c18
-rw-r--r--arch/x86/events/intel/ds.c51
-rw-r--r--arch/x86/events/intel/pt.c5
-rw-r--r--arch/x86/events/perf_event.h17
-rw-r--r--arch/x86/include/asm/intel_pt.h2
-rw-r--r--arch/x86/include/asm/msr-index.h4
7 files changed, 130 insertions, 1 deletions
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 325959d19d9a..15b90b1a8fb1 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -1005,6 +1005,27 @@ static int collect_events(struct cpu_hw_events *cpuc, struct perf_event *leader,
1005 1005
1006 /* current number of events already accepted */ 1006 /* current number of events already accepted */
1007 n = cpuc->n_events; 1007 n = cpuc->n_events;
1008 if (!cpuc->n_events)
1009 cpuc->pebs_output = 0;
1010
1011 if (!cpuc->is_fake && leader->attr.precise_ip) {
1012 /*
1013 * For PEBS->PT, if !aux_event, the group leader (PT) went
1014 * away, the group was broken down and this singleton event
1015 * can't schedule any more.
1016 */
1017 if (is_pebs_pt(leader) && !leader->aux_event)
1018 return -EINVAL;
1019
1020 /*
1021 * pebs_output: 0: no PEBS so far, 1: PT, 2: DS
1022 */
1023 if (cpuc->pebs_output &&
1024 cpuc->pebs_output != is_pebs_pt(leader) + 1)
1025 return -EINVAL;
1026
1027 cpuc->pebs_output = is_pebs_pt(leader) + 1;
1028 }
1008 1029
1009 if (is_x86_event(leader)) { 1030 if (is_x86_event(leader)) {
1010 if (n >= max_count) 1031 if (n >= max_count)
@@ -2241,6 +2262,17 @@ static int x86_pmu_check_period(struct perf_event *event, u64 value)
2241 return 0; 2262 return 0;
2242} 2263}
2243 2264
2265static int x86_pmu_aux_output_match(struct perf_event *event)
2266{
2267 if (!(pmu.capabilities & PERF_PMU_CAP_AUX_OUTPUT))
2268 return 0;
2269
2270 if (x86_pmu.aux_output_match)
2271 return x86_pmu.aux_output_match(event);
2272
2273 return 0;
2274}
2275
2244static struct pmu pmu = { 2276static struct pmu pmu = {
2245 .pmu_enable = x86_pmu_enable, 2277 .pmu_enable = x86_pmu_enable,
2246 .pmu_disable = x86_pmu_disable, 2278 .pmu_disable = x86_pmu_disable,
@@ -2266,6 +2298,8 @@ static struct pmu pmu = {
2266 .sched_task = x86_pmu_sched_task, 2298 .sched_task = x86_pmu_sched_task,
2267 .task_ctx_size = sizeof(struct x86_perf_task_context), 2299 .task_ctx_size = sizeof(struct x86_perf_task_context),
2268 .check_period = x86_pmu_check_period, 2300 .check_period = x86_pmu_check_period,
2301
2302 .aux_output_match = x86_pmu_aux_output_match,
2269}; 2303};
2270 2304
2271void arch_perf_update_userpage(struct perf_event *event, 2305void arch_perf_update_userpage(struct perf_event *event,
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 648260b5f367..28459f4b795a 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -18,6 +18,7 @@
18#include <asm/cpufeature.h> 18#include <asm/cpufeature.h>
19#include <asm/hardirq.h> 19#include <asm/hardirq.h>
20#include <asm/intel-family.h> 20#include <asm/intel-family.h>
21#include <asm/intel_pt.h>
21#include <asm/apic.h> 22#include <asm/apic.h>
22#include <asm/cpu_device_id.h> 23#include <asm/cpu_device_id.h>
23 24
@@ -3298,6 +3299,13 @@ static int intel_pmu_hw_config(struct perf_event *event)
3298 } 3299 }
3299 } 3300 }
3300 3301
3302 if (event->attr.aux_output) {
3303 if (!event->attr.precise_ip)
3304 return -EINVAL;
3305
3306 event->hw.flags |= PERF_X86_EVENT_PEBS_VIA_PT;
3307 }
3308
3301 if (event->attr.type != PERF_TYPE_RAW) 3309 if (event->attr.type != PERF_TYPE_RAW)
3302 return 0; 3310 return 0;
3303 3311
@@ -3811,6 +3819,14 @@ static int intel_pmu_check_period(struct perf_event *event, u64 value)
3811 return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0; 3819 return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0;
3812} 3820}
3813 3821
3822static int intel_pmu_aux_output_match(struct perf_event *event)
3823{
3824 if (!x86_pmu.intel_cap.pebs_output_pt_available)
3825 return 0;
3826
3827 return is_intel_pt_event(event);
3828}
3829
3814PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63"); 3830PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
3815 3831
3816PMU_FORMAT_ATTR(ldlat, "config1:0-15"); 3832PMU_FORMAT_ATTR(ldlat, "config1:0-15");
@@ -3935,6 +3951,8 @@ static __initconst const struct x86_pmu intel_pmu = {
3935 .sched_task = intel_pmu_sched_task, 3951 .sched_task = intel_pmu_sched_task,
3936 3952
3937 .check_period = intel_pmu_check_period, 3953 .check_period = intel_pmu_check_period,
3954
3955 .aux_output_match = intel_pmu_aux_output_match,
3938}; 3956};
3939 3957
3940static __init void intel_clovertown_quirk(void) 3958static __init void intel_clovertown_quirk(void)
diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c
index f1269e804e9b..ce83950036c5 100644
--- a/arch/x86/events/intel/ds.c
+++ b/arch/x86/events/intel/ds.c
@@ -902,6 +902,9 @@ struct event_constraint *intel_pebs_constraints(struct perf_event *event)
902 */ 902 */
903static inline bool pebs_needs_sched_cb(struct cpu_hw_events *cpuc) 903static inline bool pebs_needs_sched_cb(struct cpu_hw_events *cpuc)
904{ 904{
905 if (cpuc->n_pebs == cpuc->n_pebs_via_pt)
906 return false;
907
905 return cpuc->n_pebs && (cpuc->n_pebs == cpuc->n_large_pebs); 908 return cpuc->n_pebs && (cpuc->n_pebs == cpuc->n_large_pebs);
906} 909}
907 910
@@ -919,6 +922,9 @@ static inline void pebs_update_threshold(struct cpu_hw_events *cpuc)
919 u64 threshold; 922 u64 threshold;
920 int reserved; 923 int reserved;
921 924
925 if (cpuc->n_pebs_via_pt)
926 return;
927
922 if (x86_pmu.flags & PMU_FL_PEBS_ALL) 928 if (x86_pmu.flags & PMU_FL_PEBS_ALL)
923 reserved = x86_pmu.max_pebs_events + x86_pmu.num_counters_fixed; 929 reserved = x86_pmu.max_pebs_events + x86_pmu.num_counters_fixed;
924 else 930 else
@@ -1059,10 +1065,40 @@ void intel_pmu_pebs_add(struct perf_event *event)
1059 cpuc->n_pebs++; 1065 cpuc->n_pebs++;
1060 if (hwc->flags & PERF_X86_EVENT_LARGE_PEBS) 1066 if (hwc->flags & PERF_X86_EVENT_LARGE_PEBS)
1061 cpuc->n_large_pebs++; 1067 cpuc->n_large_pebs++;
1068 if (hwc->flags & PERF_X86_EVENT_PEBS_VIA_PT)
1069 cpuc->n_pebs_via_pt++;
1062 1070
1063 pebs_update_state(needed_cb, cpuc, event, true); 1071 pebs_update_state(needed_cb, cpuc, event, true);
1064} 1072}
1065 1073
1074static void intel_pmu_pebs_via_pt_disable(struct perf_event *event)
1075{
1076 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
1077
1078 if (!is_pebs_pt(event))
1079 return;
1080
1081 if (!(cpuc->pebs_enabled & ~PEBS_VIA_PT_MASK))
1082 cpuc->pebs_enabled &= ~PEBS_VIA_PT_MASK;
1083}
1084
1085static void intel_pmu_pebs_via_pt_enable(struct perf_event *event)
1086{
1087 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
1088 struct hw_perf_event *hwc = &event->hw;
1089 struct debug_store *ds = cpuc->ds;
1090
1091 if (!is_pebs_pt(event))
1092 return;
1093
1094 if (!(event->hw.flags & PERF_X86_EVENT_LARGE_PEBS))
1095 cpuc->pebs_enabled |= PEBS_PMI_AFTER_EACH_RECORD;
1096
1097 cpuc->pebs_enabled |= PEBS_OUTPUT_PT;
1098
1099 wrmsrl(MSR_RELOAD_PMC0 + hwc->idx, ds->pebs_event_reset[hwc->idx]);
1100}
1101
1066void intel_pmu_pebs_enable(struct perf_event *event) 1102void intel_pmu_pebs_enable(struct perf_event *event)
1067{ 1103{
1068 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 1104 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
@@ -1100,6 +1136,8 @@ void intel_pmu_pebs_enable(struct perf_event *event)
1100 } else { 1136 } else {
1101 ds->pebs_event_reset[hwc->idx] = 0; 1137 ds->pebs_event_reset[hwc->idx] = 0;
1102 } 1138 }
1139
1140 intel_pmu_pebs_via_pt_enable(event);
1103} 1141}
1104 1142
1105void intel_pmu_pebs_del(struct perf_event *event) 1143void intel_pmu_pebs_del(struct perf_event *event)
@@ -1111,6 +1149,8 @@ void intel_pmu_pebs_del(struct perf_event *event)
1111 cpuc->n_pebs--; 1149 cpuc->n_pebs--;
1112 if (hwc->flags & PERF_X86_EVENT_LARGE_PEBS) 1150 if (hwc->flags & PERF_X86_EVENT_LARGE_PEBS)
1113 cpuc->n_large_pebs--; 1151 cpuc->n_large_pebs--;
1152 if (hwc->flags & PERF_X86_EVENT_PEBS_VIA_PT)
1153 cpuc->n_pebs_via_pt--;
1114 1154
1115 pebs_update_state(needed_cb, cpuc, event, false); 1155 pebs_update_state(needed_cb, cpuc, event, false);
1116} 1156}
@@ -1120,7 +1160,8 @@ void intel_pmu_pebs_disable(struct perf_event *event)
1120 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 1160 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
1121 struct hw_perf_event *hwc = &event->hw; 1161 struct hw_perf_event *hwc = &event->hw;
1122 1162
1123 if (cpuc->n_pebs == cpuc->n_large_pebs) 1163 if (cpuc->n_pebs == cpuc->n_large_pebs &&
1164 cpuc->n_pebs != cpuc->n_pebs_via_pt)
1124 intel_pmu_drain_pebs_buffer(); 1165 intel_pmu_drain_pebs_buffer();
1125 1166
1126 cpuc->pebs_enabled &= ~(1ULL << hwc->idx); 1167 cpuc->pebs_enabled &= ~(1ULL << hwc->idx);
@@ -1131,6 +1172,8 @@ void intel_pmu_pebs_disable(struct perf_event *event)
1131 else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST) 1172 else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST)
1132 cpuc->pebs_enabled &= ~(1ULL << 63); 1173 cpuc->pebs_enabled &= ~(1ULL << 63);
1133 1174
1175 intel_pmu_pebs_via_pt_disable(event);
1176
1134 if (cpuc->enabled) 1177 if (cpuc->enabled)
1135 wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled); 1178 wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled);
1136 1179
@@ -2031,6 +2074,12 @@ void __init intel_ds_init(void)
2031 PERF_SAMPLE_REGS_INTR); 2074 PERF_SAMPLE_REGS_INTR);
2032 } 2075 }
2033 pr_cont("PEBS fmt4%c%s, ", pebs_type, pebs_qual); 2076 pr_cont("PEBS fmt4%c%s, ", pebs_type, pebs_qual);
2077
2078 if (x86_pmu.intel_cap.pebs_output_pt_available) {
2079 pr_cont("PEBS-via-PT, ");
2080 x86_get_pmu()->capabilities |= PERF_PMU_CAP_AUX_OUTPUT;
2081 }
2082
2034 break; 2083 break;
2035 2084
2036 default: 2085 default:
diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c
index fa43d90799cc..b1bb4d28e0be 100644
--- a/arch/x86/events/intel/pt.c
+++ b/arch/x86/events/intel/pt.c
@@ -1564,6 +1564,11 @@ void cpu_emergency_stop_pt(void)
1564 pt_event_stop(pt->handle.event, PERF_EF_UPDATE); 1564 pt_event_stop(pt->handle.event, PERF_EF_UPDATE);
1565} 1565}
1566 1566
1567int is_intel_pt_event(struct perf_event *event)
1568{
1569 return event->pmu == &pt_pmu.pmu;
1570}
1571
1567static __init int pt_init(void) 1572static __init int pt_init(void)
1568{ 1573{
1569 int ret, cpu, prior_warn = 0; 1574 int ret, cpu, prior_warn = 0;
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index 8751008fc170..ecacfbf4ebc1 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -76,6 +76,7 @@ static inline bool constraint_match(struct event_constraint *c, u64 ecode)
76#define PERF_X86_EVENT_EXCL_ACCT 0x0100 /* accounted EXCL event */ 76#define PERF_X86_EVENT_EXCL_ACCT 0x0100 /* accounted EXCL event */
77#define PERF_X86_EVENT_AUTO_RELOAD 0x0200 /* use PEBS auto-reload */ 77#define PERF_X86_EVENT_AUTO_RELOAD 0x0200 /* use PEBS auto-reload */
78#define PERF_X86_EVENT_LARGE_PEBS 0x0400 /* use large PEBS */ 78#define PERF_X86_EVENT_LARGE_PEBS 0x0400 /* use large PEBS */
79#define PERF_X86_EVENT_PEBS_VIA_PT 0x0800 /* use PT buffer for PEBS */
79 80
80struct amd_nb { 81struct amd_nb {
81 int nb_id; /* NorthBridge id */ 82 int nb_id; /* NorthBridge id */
@@ -85,6 +86,11 @@ struct amd_nb {
85}; 86};
86 87
87#define PEBS_COUNTER_MASK ((1ULL << MAX_PEBS_EVENTS) - 1) 88#define PEBS_COUNTER_MASK ((1ULL << MAX_PEBS_EVENTS) - 1)
89#define PEBS_PMI_AFTER_EACH_RECORD BIT_ULL(60)
90#define PEBS_OUTPUT_OFFSET 61
91#define PEBS_OUTPUT_MASK (3ull << PEBS_OUTPUT_OFFSET)
92#define PEBS_OUTPUT_PT (1ull << PEBS_OUTPUT_OFFSET)
93#define PEBS_VIA_PT_MASK (PEBS_OUTPUT_PT | PEBS_PMI_AFTER_EACH_RECORD)
88 94
89/* 95/*
90 * Flags PEBS can handle without an PMI. 96 * Flags PEBS can handle without an PMI.
@@ -211,6 +217,8 @@ struct cpu_hw_events {
211 u64 pebs_enabled; 217 u64 pebs_enabled;
212 int n_pebs; 218 int n_pebs;
213 int n_large_pebs; 219 int n_large_pebs;
220 int n_pebs_via_pt;
221 int pebs_output;
214 222
215 /* Current super set of events hardware configuration */ 223 /* Current super set of events hardware configuration */
216 u64 pebs_data_cfg; 224 u64 pebs_data_cfg;
@@ -510,6 +518,8 @@ union perf_capabilities {
510 */ 518 */
511 u64 full_width_write:1; 519 u64 full_width_write:1;
512 u64 pebs_baseline:1; 520 u64 pebs_baseline:1;
521 u64 pebs_metrics_available:1;
522 u64 pebs_output_pt_available:1;
513 }; 523 };
514 u64 capabilities; 524 u64 capabilities;
515}; 525};
@@ -692,6 +702,8 @@ struct x86_pmu {
692 * Check period value for PERF_EVENT_IOC_PERIOD ioctl. 702 * Check period value for PERF_EVENT_IOC_PERIOD ioctl.
693 */ 703 */
694 int (*check_period) (struct perf_event *event, u64 period); 704 int (*check_period) (struct perf_event *event, u64 period);
705
706 int (*aux_output_match) (struct perf_event *event);
695}; 707};
696 708
697struct x86_perf_task_context { 709struct x86_perf_task_context {
@@ -901,6 +913,11 @@ static inline int amd_pmu_init(void)
901 913
902#endif /* CONFIG_CPU_SUP_AMD */ 914#endif /* CONFIG_CPU_SUP_AMD */
903 915
916static inline int is_pebs_pt(struct perf_event *event)
917{
918 return !!(event->hw.flags & PERF_X86_EVENT_PEBS_VIA_PT);
919}
920
904#ifdef CONFIG_CPU_SUP_INTEL 921#ifdef CONFIG_CPU_SUP_INTEL
905 922
906static inline bool intel_pmu_has_bts_period(struct perf_event *event, u64 period) 923static inline bool intel_pmu_has_bts_period(struct perf_event *event, u64 period)
diff --git a/arch/x86/include/asm/intel_pt.h b/arch/x86/include/asm/intel_pt.h
index 634f99b1dc22..423b788f495e 100644
--- a/arch/x86/include/asm/intel_pt.h
+++ b/arch/x86/include/asm/intel_pt.h
@@ -28,10 +28,12 @@ enum pt_capabilities {
28void cpu_emergency_stop_pt(void); 28void cpu_emergency_stop_pt(void);
29extern u32 intel_pt_validate_hw_cap(enum pt_capabilities cap); 29extern u32 intel_pt_validate_hw_cap(enum pt_capabilities cap);
30extern u32 intel_pt_validate_cap(u32 *caps, enum pt_capabilities cap); 30extern u32 intel_pt_validate_cap(u32 *caps, enum pt_capabilities cap);
31extern int is_intel_pt_event(struct perf_event *event);
31#else 32#else
32static inline void cpu_emergency_stop_pt(void) {} 33static inline void cpu_emergency_stop_pt(void) {}
33static inline u32 intel_pt_validate_hw_cap(enum pt_capabilities cap) { return 0; } 34static inline u32 intel_pt_validate_hw_cap(enum pt_capabilities cap) { return 0; }
34static inline u32 intel_pt_validate_cap(u32 *caps, enum pt_capabilities capability) { return 0; } 35static inline u32 intel_pt_validate_cap(u32 *caps, enum pt_capabilities capability) { return 0; }
36static inline int is_intel_pt_event(struct perf_event *event) { return 0; }
35#endif 37#endif
36 38
37#endif /* _ASM_X86_INTEL_PT_H */ 39#endif /* _ASM_X86_INTEL_PT_H */
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 271d837d69a8..de753206b427 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -375,6 +375,10 @@
375/* Alternative perfctr range with full access. */ 375/* Alternative perfctr range with full access. */
376#define MSR_IA32_PMC0 0x000004c1 376#define MSR_IA32_PMC0 0x000004c1
377 377
378/* Auto-reload via MSR instead of DS area */
379#define MSR_RELOAD_PMC0 0x000014c1
380#define MSR_RELOAD_FIXED_CTR0 0x00001309
381
378/* AMD64 MSRs. Not complete. See the architecture manual for a more 382/* AMD64 MSRs. Not complete. See the architecture manual for a more
379 complete list. */ 383 complete list. */
380 384