Skip to content

Commit fda1f99

Browse files
Kan LiangPeter Zijlstra
authored andcommitted
perf/x86/intel/lbr: Factor out rdlbr_all() and wrlbr_all()
The previous model-specific LBR and Architecture LBR (legacy way) use a similar method to save/restore the LBR information, which directly accesses the LBR registers. The codes which read/write a set of LBR registers can be shared between them. Factor out two functions which are used to read/write a set of LBR registers. Add lbr_info into structure x86_pmu, and use it to replace the hardcoded LBR INFO MSR, because the LBR INFO MSR address of the previous model-specific LBR is different from Architecture LBR. The MSR address should be assigned at boot time. For now, only Sky Lake and later platforms have the LBR INFO MSR. Signed-off-by: Kan Liang <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 020d91e commit fda1f99

File tree

2 files changed

+51
-17
lines changed

2 files changed

+51
-17
lines changed

arch/x86/events/intel/lbr.c

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ void intel_pmu_lbr_reset_64(void)
237237
wrmsrl(x86_pmu.lbr_from + i, 0);
238238
wrmsrl(x86_pmu.lbr_to + i, 0);
239239
if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
240-
wrmsrl(MSR_LBR_INFO_0 + i, 0);
240+
wrmsrl(x86_pmu.lbr_info + i, 0);
241241
}
242242
}
243243

@@ -343,6 +343,11 @@ static __always_inline void wrlbr_to(unsigned int idx, u64 val)
343343
wrmsrl(x86_pmu.lbr_to + idx, val);
344344
}
345345

346+
static __always_inline void wrlbr_info(unsigned int idx, u64 val)
347+
{
348+
wrmsrl(x86_pmu.lbr_info + idx, val);
349+
}
350+
346351
static __always_inline u64 rdlbr_from(unsigned int idx)
347352
{
348353
u64 val;
@@ -361,8 +366,44 @@ static __always_inline u64 rdlbr_to(unsigned int idx)
361366
return val;
362367
}
363368

369+
static __always_inline u64 rdlbr_info(unsigned int idx)
370+
{
371+
u64 val;
372+
373+
rdmsrl(x86_pmu.lbr_info + idx, val);
374+
375+
return val;
376+
}
377+
378+
static inline void
379+
wrlbr_all(struct lbr_entry *lbr, unsigned int idx, bool need_info)
380+
{
381+
wrlbr_from(idx, lbr->from);
382+
wrlbr_to(idx, lbr->to);
383+
if (need_info)
384+
wrlbr_info(idx, lbr->info);
385+
}
386+
387+
static inline bool
388+
rdlbr_all(struct lbr_entry *lbr, unsigned int idx, bool need_info)
389+
{
390+
u64 from = rdlbr_from(idx);
391+
392+
/* Don't read invalid entry */
393+
if (!from)
394+
return false;
395+
396+
lbr->from = from;
397+
lbr->to = rdlbr_to(idx);
398+
if (need_info)
399+
lbr->info = rdlbr_info(idx);
400+
401+
return true;
402+
}
403+
364404
void intel_pmu_lbr_restore(void *ctx)
365405
{
406+
bool need_info = x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO;
366407
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
367408
struct x86_perf_task_context *task_ctx = ctx;
368409
int i;
@@ -372,19 +413,15 @@ void intel_pmu_lbr_restore(void *ctx)
372413
mask = x86_pmu.lbr_nr - 1;
373414
for (i = 0; i < task_ctx->valid_lbrs; i++) {
374415
lbr_idx = (tos - i) & mask;
375-
wrlbr_from(lbr_idx, task_ctx->lbr[i].from);
376-
wrlbr_to(lbr_idx, task_ctx->lbr[i].to);
377-
378-
if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
379-
wrmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr[i].info);
416+
wrlbr_all(&task_ctx->lbr[i], lbr_idx, need_info);
380417
}
381418

382419
for (; i < x86_pmu.lbr_nr; i++) {
383420
lbr_idx = (tos - i) & mask;
384421
wrlbr_from(lbr_idx, 0);
385422
wrlbr_to(lbr_idx, 0);
386423
if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
387-
wrmsrl(MSR_LBR_INFO_0 + lbr_idx, 0);
424+
wrlbr_info(lbr_idx, 0);
388425
}
389426

390427
wrmsrl(x86_pmu.lbr_tos, tos);
@@ -427,23 +464,19 @@ static void __intel_pmu_lbr_restore(void *ctx)
427464

428465
void intel_pmu_lbr_save(void *ctx)
429466
{
467+
bool need_info = x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO;
430468
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
431469
struct x86_perf_task_context *task_ctx = ctx;
432470
unsigned lbr_idx, mask;
433-
u64 tos, from;
471+
u64 tos;
434472
int i;
435473

436474
mask = x86_pmu.lbr_nr - 1;
437475
tos = intel_pmu_lbr_tos();
438476
for (i = 0; i < x86_pmu.lbr_nr; i++) {
439477
lbr_idx = (tos - i) & mask;
440-
from = rdlbr_from(lbr_idx);
441-
if (!from)
478+
if (!rdlbr_all(&task_ctx->lbr[i], lbr_idx, need_info))
442479
break;
443-
task_ctx->lbr[i].from = from;
444-
task_ctx->lbr[i].to = rdlbr_to(lbr_idx);
445-
if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
446-
rdmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr[i].info);
447480
}
448481
task_ctx->valid_lbrs = i;
449482
task_ctx->tos = tos;
@@ -689,7 +722,7 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
689722
if (lbr_format == LBR_FORMAT_INFO && need_info) {
690723
u64 info;
691724

692-
rdmsrl(MSR_LBR_INFO_0 + lbr_idx, info);
725+
info = rdlbr_info(lbr_idx);
693726
mis = !!(info & LBR_INFO_MISPRED);
694727
pred = !mis;
695728
in_tx = !!(info & LBR_INFO_IN_TX);
@@ -1336,6 +1369,7 @@ __init void intel_pmu_lbr_init_skl(void)
13361369
x86_pmu.lbr_tos = MSR_LBR_TOS;
13371370
x86_pmu.lbr_from = MSR_LBR_NHM_FROM;
13381371
x86_pmu.lbr_to = MSR_LBR_NHM_TO;
1372+
x86_pmu.lbr_info = MSR_LBR_INFO_0;
13391373

13401374
x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
13411375
x86_pmu.lbr_sel_map = hsw_lbr_sel_map;
@@ -1421,7 +1455,7 @@ int x86_perf_get_lbr(struct x86_pmu_lbr *lbr)
14211455
lbr->nr = x86_pmu.lbr_nr;
14221456
lbr->from = x86_pmu.lbr_from;
14231457
lbr->to = x86_pmu.lbr_to;
1424-
lbr->info = (lbr_fmt == LBR_FORMAT_INFO) ? MSR_LBR_INFO_0 : 0;
1458+
lbr->info = (lbr_fmt == LBR_FORMAT_INFO) ? x86_pmu.lbr_info : 0;
14251459

14261460
return 0;
14271461
}

arch/x86/events/perf_event.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ struct x86_pmu {
690690
* Intel LBR
691691
*/
692692
unsigned int lbr_tos, lbr_from, lbr_to,
693-
lbr_nr; /* LBR base regs and size */
693+
lbr_info, lbr_nr; /* LBR base regs and size */
694694
union {
695695
u64 lbr_sel_mask; /* LBR_SELECT valid bits */
696696
u64 lbr_ctl_mask; /* LBR_CTL valid bits */

0 commit comments

Comments
 (0)