diff options
author | Peter Zijlstra <peterz@infradead.org> | 2015-05-12 15:18:18 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-06-07 16:09:16 +0200 |
commit | a3d86542de8850be52e8589da22b24002941dfb7 (patch) | |
tree | 32f252229099a23651f036ad780cd24cdb58bbe0 /arch | |
parent | c4937a91ea56b546234b0608a413ebad90536d26 (diff) |
perf/x86/intel/pebs: Add PEBSv3 decoding
PEBSv3 as present on Skylake fixed the long standing issue of the
status bits. They now really reflect the events that generated the
record.
Tested-by: Andi Kleen <ak@linux.intel.com>
Tested-by: Kan Liang <kan.liang@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_ds.c | 30 |
1 files changed, 19 insertions, 11 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 34d0c4816141..71fc40238843 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -1034,6 +1034,9 @@ get_next_pebs_record_by_bit(void *base, void *top, int bit) struct pebs_record_nhm *p = at; if (test_bit(bit, (unsigned long *)&p->status)) { + /* PEBS v3 has accurate status bits */ + if (x86_pmu.intel_cap.pebs_format >= 3) + return at; if (p->status == (1 << bit)) return at; @@ -1055,20 +1058,18 @@ static void __intel_pmu_pebs_event(struct perf_event *event, { struct perf_sample_data data; struct pt_regs regs; - int i; void *at = get_next_pebs_record_by_bit(base, top, bit); if (!intel_pmu_save_and_restart(event) && !(event->hw.flags & PERF_X86_EVENT_AUTO_RELOAD)) return; - if (count > 1) { - for (i = 0; i < count - 1; i++) { - setup_pebs_sample_data(event, iregs, at, &data, ®s); - perf_event_output(event, &data, ®s); - at += x86_pmu.pebs_record_size; - at = get_next_pebs_record_by_bit(at, top, bit); - } + while (count > 1) { + setup_pebs_sample_data(event, iregs, at, &data, ®s); + perf_event_output(event, &data, ®s); + at += x86_pmu.pebs_record_size; + at = get_next_pebs_record_by_bit(at, top, bit); + count--; } setup_pebs_sample_data(event, iregs, at, &data, ®s); @@ -1124,9 +1125,9 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) struct debug_store *ds = cpuc->ds; struct perf_event *event; void *base, *at, *top; - int bit; short counts[MAX_PEBS_EVENTS] = {}; short error[MAX_PEBS_EVENTS] = {}; + int bit, i; if (!x86_pmu.pebs_active) return; @@ -1142,6 +1143,15 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) for (at = base; at < top; at += x86_pmu.pebs_record_size) { struct pebs_record_nhm *p = at; + /* PEBS v3 has accurate status bits */ + if (x86_pmu.intel_cap.pebs_format >= 3) { + for_each_set_bit(bit, (unsigned long *)&p->status, + MAX_PEBS_EVENTS) + counts[bit]++; + + continue; + } + bit = find_first_bit((unsigned long *)&p->status, x86_pmu.max_pebs_events); if (bit >= x86_pmu.max_pebs_events) @@ -1171,8 +1181,6 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) pebs_status = p->status & cpuc->pebs_enabled; pebs_status &= (1ULL << MAX_PEBS_EVENTS) - 1; if (pebs_status != (1 << bit)) { - u8 i; - for_each_set_bit(i, (unsigned long *)&pebs_status, MAX_PEBS_EVENTS) error[i]++; |