Skip to content

Commit 50eab8f

Browse files
Andi KleenIngo Molnar
authored andcommitted
perf/x86/intel/lbr: Add support for LBRv5
Add support for the new LBRv5 format used on Intel Skylake CPUs. The flags for mispredict, abort, in_tx etc. moved to range of separate LBR_INFO_* MSRs. Teach the LBR code to read those. The original LBR registers stay the same, except they have full sign extension now. LBR_INFO also reports a cycle count to the last branch. Report the cycle information using the new "cycles" branch_info output field. In addition we have to context switch and clear the new INFO MSRs to avoid any information leaks. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: eranian@google.com Link: http://lkml.kernel.org/r/1431285767-27027-6-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent 71ef3c6 commit 50eab8f

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

arch/x86/kernel/cpu/perf_event.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ struct x86_pmu {
625625
struct x86_perf_task_context {
626626
u64 lbr_from[MAX_LBR_ENTRIES];
627627
u64 lbr_to[MAX_LBR_ENTRIES];
628+
u64 lbr_info[MAX_LBR_ENTRIES];
628629
int lbr_callstack_users;
629630
int lbr_stack_state;
630631
};

arch/x86/kernel/cpu/perf_event_intel_lbr.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ enum {
1313
LBR_FORMAT_EIP = 0x02,
1414
LBR_FORMAT_EIP_FLAGS = 0x03,
1515
LBR_FORMAT_EIP_FLAGS2 = 0x04,
16-
LBR_FORMAT_MAX_KNOWN = LBR_FORMAT_EIP_FLAGS2,
16+
LBR_FORMAT_INFO = 0x05,
17+
LBR_FORMAT_MAX_KNOWN = LBR_FORMAT_INFO,
1718
};
1819

1920
static enum {
@@ -186,6 +187,8 @@ static void intel_pmu_lbr_reset_64(void)
186187
for (i = 0; i < x86_pmu.lbr_nr; i++) {
187188
wrmsrl(x86_pmu.lbr_from + i, 0);
188189
wrmsrl(x86_pmu.lbr_to + i, 0);
190+
if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
191+
wrmsrl(MSR_LBR_INFO_0 + i, 0);
189192
}
190193
}
191194

@@ -234,6 +237,8 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
234237
lbr_idx = (tos - i) & mask;
235238
wrmsrl(x86_pmu.lbr_from + lbr_idx, task_ctx->lbr_from[i]);
236239
wrmsrl(x86_pmu.lbr_to + lbr_idx, task_ctx->lbr_to[i]);
240+
if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
241+
wrmsrl(MSR_LBR_INFO_0 + i, task_ctx->lbr_info[i]);
237242
}
238243
task_ctx->lbr_stack_state = LBR_NONE;
239244
}
@@ -255,6 +260,8 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
255260
lbr_idx = (tos - i) & mask;
256261
rdmsrl(x86_pmu.lbr_from + lbr_idx, task_ctx->lbr_from[i]);
257262
rdmsrl(x86_pmu.lbr_to + lbr_idx, task_ctx->lbr_to[i]);
263+
if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
264+
rdmsrl(MSR_LBR_INFO_0 + i, task_ctx->lbr_info[i]);
258265
}
259266
task_ctx->lbr_stack_state = LBR_VALID;
260267
}
@@ -416,11 +423,22 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
416423
unsigned long lbr_idx = (tos - i) & mask;
417424
u64 from, to, mis = 0, pred = 0, in_tx = 0, abort = 0;
418425
int skip = 0;
426+
u16 cycles = 0;
419427
int lbr_flags = lbr_desc[lbr_format];
420428

421429
rdmsrl(x86_pmu.lbr_from + lbr_idx, from);
422430
rdmsrl(x86_pmu.lbr_to + lbr_idx, to);
423431

432+
if (lbr_format == LBR_FORMAT_INFO) {
433+
u64 info;
434+
435+
rdmsrl(MSR_LBR_INFO_0 + lbr_idx, info);
436+
mis = !!(info & LBR_INFO_MISPRED);
437+
pred = !mis;
438+
in_tx = !!(info & LBR_INFO_IN_TX);
439+
abort = !!(info & LBR_INFO_ABORT);
440+
cycles = (info & LBR_INFO_CYCLES);
441+
}
424442
if (lbr_flags & LBR_EIP_FLAGS) {
425443
mis = !!(from & LBR_FROM_FLAG_MISPRED);
426444
pred = !mis;
@@ -450,6 +468,7 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
450468
cpuc->lbr_entries[out].predicted = pred;
451469
cpuc->lbr_entries[out].in_tx = in_tx;
452470
cpuc->lbr_entries[out].abort = abort;
471+
cpuc->lbr_entries[out].cycles = cycles;
453472
cpuc->lbr_entries[out].reserved = 0;
454473
out++;
455474
}

0 commit comments

Comments
 (0)