Skip to content

Commit 799571b

Browse files
Kan LiangPeter Zijlstra
authored andcommitted
perf/x86/intel/lbr: Add the function pointers for LBR save and restore
The MSRs of Architectural LBR are different from previous model-specific LBR. Perf has to implement different functions to save and restore them. The function pointers for LBR save and restore are introduced. Perf should initialize the corresponding functions at boot time. The generic optimizations, e.g. avoiding restore LBR if no one else touched them, still apply for Architectural LBRs. The related codes are not moved to model-specific functions. Current model-specific LBR functions are set as default. 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 c301b1d commit 799571b

File tree

3 files changed

+59
-30
lines changed

3 files changed

+59
-30
lines changed

arch/x86/events/intel/core.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3981,6 +3981,8 @@ static __initconst const struct x86_pmu core_pmu = {
39813981

39823982
.lbr_reset = intel_pmu_lbr_reset_64,
39833983
.lbr_read = intel_pmu_lbr_read_64,
3984+
.lbr_save = intel_pmu_lbr_save,
3985+
.lbr_restore = intel_pmu_lbr_restore,
39843986
};
39853987

39863988
static __initconst const struct x86_pmu intel_pmu = {
@@ -4029,6 +4031,8 @@ static __initconst const struct x86_pmu intel_pmu = {
40294031

40304032
.lbr_reset = intel_pmu_lbr_reset_64,
40314033
.lbr_read = intel_pmu_lbr_read_64,
4034+
.lbr_save = intel_pmu_lbr_save,
4035+
.lbr_restore = intel_pmu_lbr_restore,
40324036
};
40334037

40344038
static __init void intel_clovertown_quirk(void)

arch/x86/events/intel/lbr.c

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -323,31 +323,13 @@ static inline u64 rdlbr_to(unsigned int idx)
323323
return val;
324324
}
325325

326-
static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
326+
void intel_pmu_lbr_restore(void *ctx)
327327
{
328328
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
329+
struct x86_perf_task_context *task_ctx = ctx;
329330
int i;
330331
unsigned lbr_idx, mask;
331-
u64 tos;
332-
333-
if (task_ctx->lbr_callstack_users == 0 ||
334-
task_ctx->lbr_stack_state == LBR_NONE) {
335-
intel_pmu_lbr_reset();
336-
return;
337-
}
338-
339-
tos = task_ctx->tos;
340-
/*
341-
* Does not restore the LBR registers, if
342-
* - No one else touched them, and
343-
* - Did not enter C6
344-
*/
345-
if ((task_ctx == cpuc->last_task_ctx) &&
346-
(task_ctx->log_id == cpuc->last_log_id) &&
347-
rdlbr_from(tos)) {
348-
task_ctx->lbr_stack_state = LBR_NONE;
349-
return;
350-
}
332+
u64 tos = task_ctx->tos;
351333

352334
mask = x86_pmu.lbr_nr - 1;
353335
for (i = 0; i < task_ctx->valid_lbrs; i++) {
@@ -368,24 +350,48 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
368350
}
369351

370352
wrmsrl(x86_pmu.lbr_tos, tos);
371-
task_ctx->lbr_stack_state = LBR_NONE;
372353

373354
if (cpuc->lbr_select)
374355
wrmsrl(MSR_LBR_SELECT, task_ctx->lbr_sel);
375356
}
376357

377-
static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
358+
static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
378359
{
379360
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
380-
unsigned lbr_idx, mask;
381-
u64 tos, from;
382-
int i;
361+
u64 tos;
383362

384-
if (task_ctx->lbr_callstack_users == 0) {
363+
if (task_ctx->lbr_callstack_users == 0 ||
364+
task_ctx->lbr_stack_state == LBR_NONE) {
365+
intel_pmu_lbr_reset();
366+
return;
367+
}
368+
369+
tos = task_ctx->tos;
370+
/*
371+
* Does not restore the LBR registers, if
372+
* - No one else touched them, and
373+
* - Did not enter C6
374+
*/
375+
if ((task_ctx == cpuc->last_task_ctx) &&
376+
(task_ctx->log_id == cpuc->last_log_id) &&
377+
rdlbr_from(tos)) {
385378
task_ctx->lbr_stack_state = LBR_NONE;
386379
return;
387380
}
388381

382+
x86_pmu.lbr_restore(task_ctx);
383+
384+
task_ctx->lbr_stack_state = LBR_NONE;
385+
}
386+
387+
void intel_pmu_lbr_save(void *ctx)
388+
{
389+
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
390+
struct x86_perf_task_context *task_ctx = ctx;
391+
unsigned lbr_idx, mask;
392+
u64 tos, from;
393+
int i;
394+
389395
mask = x86_pmu.lbr_nr - 1;
390396
tos = intel_pmu_lbr_tos();
391397
for (i = 0; i < x86_pmu.lbr_nr; i++) {
@@ -400,13 +406,26 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
400406
}
401407
task_ctx->valid_lbrs = i;
402408
task_ctx->tos = tos;
409+
410+
if (cpuc->lbr_select)
411+
rdmsrl(MSR_LBR_SELECT, task_ctx->lbr_sel);
412+
}
413+
414+
static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
415+
{
416+
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
417+
418+
if (task_ctx->lbr_callstack_users == 0) {
419+
task_ctx->lbr_stack_state = LBR_NONE;
420+
return;
421+
}
422+
423+
x86_pmu.lbr_save(task_ctx);
424+
403425
task_ctx->lbr_stack_state = LBR_VALID;
404426

405427
cpuc->last_task_ctx = task_ctx;
406428
cpuc->last_log_id = ++task_ctx->log_id;
407-
408-
if (cpuc->lbr_select)
409-
rdmsrl(MSR_LBR_SELECT, task_ctx->lbr_sel);
410429
}
411430

412431
void intel_pmu_lbr_swap_task_ctx(struct perf_event_context *prev,

arch/x86/events/perf_event.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,8 @@ struct x86_pmu {
695695

696696
void (*lbr_reset)(void);
697697
void (*lbr_read)(struct cpu_hw_events *cpuc);
698+
void (*lbr_save)(void *ctx);
699+
void (*lbr_restore)(void *ctx);
698700

699701
/*
700702
* Intel PT/LBR/BTS are exclusive
@@ -1090,6 +1092,10 @@ void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc);
10901092

10911093
void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc);
10921094

1095+
void intel_pmu_lbr_save(void *ctx);
1096+
1097+
void intel_pmu_lbr_restore(void *ctx);
1098+
10931099
void intel_pmu_lbr_init_core(void);
10941100

10951101
void intel_pmu_lbr_init_nhm(void);

0 commit comments

Comments
 (0)