|
@@ -216,6 +216,8 @@ static void intel_pmu_lbr_reset_64(void)
|
|
|
|
|
|
void intel_pmu_lbr_reset(void)
|
|
|
{
|
|
|
+ struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
|
|
|
+
|
|
|
if (!x86_pmu.lbr_nr)
|
|
|
return;
|
|
|
|
|
@@ -223,6 +225,9 @@ void intel_pmu_lbr_reset(void)
|
|
|
intel_pmu_lbr_reset_32();
|
|
|
else
|
|
|
intel_pmu_lbr_reset_64();
|
|
|
+
|
|
|
+ cpuc->last_task_ctx = NULL;
|
|
|
+ cpuc->last_log_id = 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -334,6 +339,7 @@ static inline u64 rdlbr_to(unsigned int idx)
|
|
|
|
|
|
static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
|
|
|
{
|
|
|
+ struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
|
|
|
int i;
|
|
|
unsigned lbr_idx, mask;
|
|
|
u64 tos;
|
|
@@ -344,8 +350,20 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- mask = x86_pmu.lbr_nr - 1;
|
|
|
tos = task_ctx->tos;
|
|
|
+ /*
|
|
|
+ * Does not restore the LBR registers, if
|
|
|
+ * - No one else touched them, and
|
|
|
+ * - Did not enter C6
|
|
|
+ */
|
|
|
+ if ((task_ctx == cpuc->last_task_ctx) &&
|
|
|
+ (task_ctx->log_id == cpuc->last_log_id) &&
|
|
|
+ rdlbr_from(tos)) {
|
|
|
+ task_ctx->lbr_stack_state = LBR_NONE;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ mask = x86_pmu.lbr_nr - 1;
|
|
|
for (i = 0; i < task_ctx->valid_lbrs; i++) {
|
|
|
lbr_idx = (tos - i) & mask;
|
|
|
wrlbr_from(lbr_idx, task_ctx->lbr_from[i]);
|
|
@@ -369,6 +387,7 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
|
|
|
|
|
|
static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
|
|
|
{
|
|
|
+ struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
|
|
|
unsigned lbr_idx, mask;
|
|
|
u64 tos, from;
|
|
|
int i;
|
|
@@ -393,6 +412,9 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
|
|
|
task_ctx->valid_lbrs = i;
|
|
|
task_ctx->tos = tos;
|
|
|
task_ctx->lbr_stack_state = LBR_VALID;
|
|
|
+
|
|
|
+ cpuc->last_task_ctx = task_ctx;
|
|
|
+ cpuc->last_log_id = ++task_ctx->log_id;
|
|
|
}
|
|
|
|
|
|
void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in)
|