Skip to content

Commit f42be86

Browse files
Kan LiangPeter Zijlstra
authored andcommitted
perf/x86/intel/lbr: Use dynamic data structure for task_ctx
The type of task_ctx is hardcoded as struct x86_perf_task_context, which doesn't apply for Architecture LBR. For example, Architecture LBR doesn't have the TOS MSR. The number of LBR entries is variable. A new struct will be introduced for Architecture LBR. Perf has to determine the type of task_ctx at run time. The type of task_ctx pointer is changed to 'void *', which will be determined at run time. The generic LBR optimization can be shared between Architecture LBR and model-specific LBR. Both need to access the structure for the generic LBR optimization. A helper task_context_opt() is introduced to retrieve the pointer of the structure at run time. 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 530bfff commit f42be86

File tree

2 files changed

+32
-34
lines changed

2 files changed

+32
-34
lines changed

arch/x86/events/intel/lbr.c

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -355,18 +355,17 @@ void intel_pmu_lbr_restore(void *ctx)
355355
wrmsrl(MSR_LBR_SELECT, task_ctx->lbr_sel);
356356
}
357357

358-
static __always_inline bool
359-
lbr_is_reset_in_cstate(struct x86_perf_task_context *task_ctx)
358+
static __always_inline bool lbr_is_reset_in_cstate(void *ctx)
360359
{
361-
return !rdlbr_from(task_ctx->tos);
360+
return !rdlbr_from(((struct x86_perf_task_context *)ctx)->tos);
362361
}
363362

364-
static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
363+
static void __intel_pmu_lbr_restore(void *ctx)
365364
{
366365
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
367366

368-
if (task_ctx->opt.lbr_callstack_users == 0 ||
369-
task_ctx->opt.lbr_stack_state == LBR_NONE) {
367+
if (task_context_opt(ctx)->lbr_callstack_users == 0 ||
368+
task_context_opt(ctx)->lbr_stack_state == LBR_NONE) {
370369
intel_pmu_lbr_reset();
371370
return;
372371
}
@@ -376,16 +375,16 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
376375
* - No one else touched them, and
377376
* - Was not cleared in Cstate
378377
*/
379-
if ((task_ctx == cpuc->last_task_ctx) &&
380-
(task_ctx->opt.log_id == cpuc->last_log_id) &&
381-
!lbr_is_reset_in_cstate(task_ctx)) {
382-
task_ctx->opt.lbr_stack_state = LBR_NONE;
378+
if ((ctx == cpuc->last_task_ctx) &&
379+
(task_context_opt(ctx)->log_id == cpuc->last_log_id) &&
380+
!lbr_is_reset_in_cstate(ctx)) {
381+
task_context_opt(ctx)->lbr_stack_state = LBR_NONE;
383382
return;
384383
}
385384

386-
x86_pmu.lbr_restore(task_ctx);
385+
x86_pmu.lbr_restore(ctx);
387386

388-
task_ctx->opt.lbr_stack_state = LBR_NONE;
387+
task_context_opt(ctx)->lbr_stack_state = LBR_NONE;
389388
}
390389

391390
void intel_pmu_lbr_save(void *ctx)
@@ -415,27 +414,27 @@ void intel_pmu_lbr_save(void *ctx)
415414
rdmsrl(MSR_LBR_SELECT, task_ctx->lbr_sel);
416415
}
417416

418-
static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
417+
static void __intel_pmu_lbr_save(void *ctx)
419418
{
420419
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
421420

422-
if (task_ctx->opt.lbr_callstack_users == 0) {
423-
task_ctx->opt.lbr_stack_state = LBR_NONE;
421+
if (task_context_opt(ctx)->lbr_callstack_users == 0) {
422+
task_context_opt(ctx)->lbr_stack_state = LBR_NONE;
424423
return;
425424
}
426425

427-
x86_pmu.lbr_save(task_ctx);
426+
x86_pmu.lbr_save(ctx);
428427

429-
task_ctx->opt.lbr_stack_state = LBR_VALID;
428+
task_context_opt(ctx)->lbr_stack_state = LBR_VALID;
430429

431-
cpuc->last_task_ctx = task_ctx;
432-
cpuc->last_log_id = ++task_ctx->opt.log_id;
430+
cpuc->last_task_ctx = ctx;
431+
cpuc->last_log_id = ++task_context_opt(ctx)->log_id;
433432
}
434433

435434
void intel_pmu_lbr_swap_task_ctx(struct perf_event_context *prev,
436435
struct perf_event_context *next)
437436
{
438-
struct x86_perf_task_context *prev_ctx_data, *next_ctx_data;
437+
void *prev_ctx_data, *next_ctx_data;
439438

440439
swap(prev->task_ctx_data, next->task_ctx_data);
441440

@@ -451,14 +450,14 @@ void intel_pmu_lbr_swap_task_ctx(struct perf_event_context *prev,
451450
if (!prev_ctx_data || !next_ctx_data)
452451
return;
453452

454-
swap(prev_ctx_data->opt.lbr_callstack_users,
455-
next_ctx_data->opt.lbr_callstack_users);
453+
swap(task_context_opt(prev_ctx_data)->lbr_callstack_users,
454+
task_context_opt(next_ctx_data)->lbr_callstack_users);
456455
}
457456

458457
void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in)
459458
{
460459
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
461-
struct x86_perf_task_context *task_ctx;
460+
void *task_ctx;
462461

463462
if (!cpuc->lbr_users)
464463
return;
@@ -495,7 +494,6 @@ static inline bool branch_user_callstack(unsigned br_sel)
495494
void intel_pmu_lbr_add(struct perf_event *event)
496495
{
497496
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
498-
struct x86_perf_task_context *task_ctx;
499497

500498
if (!x86_pmu.lbr_nr)
501499
return;
@@ -505,10 +503,8 @@ void intel_pmu_lbr_add(struct perf_event *event)
505503

506504
cpuc->br_sel = event->hw.branch_reg.reg;
507505

508-
if (branch_user_callstack(cpuc->br_sel) && event->ctx->task_ctx_data) {
509-
task_ctx = event->ctx->task_ctx_data;
510-
task_ctx->opt.lbr_callstack_users++;
511-
}
506+
if (branch_user_callstack(cpuc->br_sel) && event->ctx->task_ctx_data)
507+
task_context_opt(event->ctx->task_ctx_data)->lbr_callstack_users++;
512508

513509
/*
514510
* Request pmu::sched_task() callback, which will fire inside the
@@ -539,16 +535,13 @@ void intel_pmu_lbr_add(struct perf_event *event)
539535
void intel_pmu_lbr_del(struct perf_event *event)
540536
{
541537
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
542-
struct x86_perf_task_context *task_ctx;
543538

544539
if (!x86_pmu.lbr_nr)
545540
return;
546541

547542
if (branch_user_callstack(cpuc->br_sel) &&
548-
event->ctx->task_ctx_data) {
549-
task_ctx = event->ctx->task_ctx_data;
550-
task_ctx->opt.lbr_callstack_users--;
551-
}
543+
event->ctx->task_ctx_data)
544+
task_context_opt(event->ctx->task_ctx_data)->lbr_callstack_users--;
552545

553546
if (event->hw.flags & PERF_X86_EVENT_LBR_SELECT)
554547
cpuc->lbr_select = 0;

arch/x86/events/perf_event.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ struct cpu_hw_events {
247247
struct perf_branch_entry lbr_entries[MAX_LBR_ENTRIES];
248248
struct er_account *lbr_sel;
249249
u64 br_sel;
250-
struct x86_perf_task_context *last_task_ctx;
250+
void *last_task_ctx;
251251
int last_log_id;
252252
int lbr_select;
253253

@@ -800,6 +800,11 @@ static struct perf_pmu_events_ht_attr event_attr_##v = { \
800800
struct pmu *x86_get_pmu(void);
801801
extern struct x86_pmu x86_pmu __read_mostly;
802802

803+
static __always_inline struct x86_perf_task_context_opt *task_context_opt(void *ctx)
804+
{
805+
return &((struct x86_perf_task_context *)ctx)->opt;
806+
}
807+
803808
static inline bool x86_pmu_has_lbr_callstack(void)
804809
{
805810
return x86_pmu.lbr_sel_map &&

0 commit comments

Comments
 (0)