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>
This commit is contained in:
Родитель
c4937a91ea
Коммит
a3d86542de
|
@ -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]++;
|
||||
|
|
Загрузка…
Ссылка в новой задаче