aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorYan, Zheng <zheng.z.yan@intel.com>2014-11-04 21:55:59 -0500
committerIngo Molnar <mingo@kernel.org>2015-02-18 11:16:03 -0500
commit2a0ad3b326a9024ba86dca4028499d31fa0c6c4d (patch)
tree3c710a73ad62005b1e60ebe9f32a8235604de43e /arch/x86
parentba532500c5651a4be4108acc64ed99a95cb005b3 (diff)
perf/x86/intel: Use context switch callback to flush LBR stack
Previous commit introduces context switch callback, its function overlaps with the flush branch stack callback. So we can use the context switch callback to flush LBR stack. This patch adds code that uses the flush branch callback to flush the LBR stack when task is being scheduled in. The callback is enabled only when there are events use the LBR hardware. This patch also removes all old flush branch stack code. Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com> Signed-off-by: Kan Liang <kan.liang@intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Arnaldo Carvalho de Melo <acme@kernel.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Vince Weaver <vincent.weaver@maine.edu> Cc: eranian@google.com Cc: jolsa@redhat.com Link: http://lkml.kernel.org/r/1415156173-10035-4-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/cpu/perf_event.c7
-rw-r--r--arch/x86/kernel/cpu/perf_event.h3
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c14
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_lbr.c27
4 files changed, 30 insertions, 21 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 0efbd6cc2966..6b1fd26a37cf 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1920,12 +1920,6 @@ static void x86_pmu_sched_task(struct perf_event_context *ctx, bool sched_in)
1920 x86_pmu.sched_task(ctx, sched_in); 1920 x86_pmu.sched_task(ctx, sched_in);
1921} 1921}
1922 1922
1923static void x86_pmu_flush_branch_stack(void)
1924{
1925 if (x86_pmu.flush_branch_stack)
1926 x86_pmu.flush_branch_stack();
1927}
1928
1929void perf_check_microcode(void) 1923void perf_check_microcode(void)
1930{ 1924{
1931 if (x86_pmu.check_microcode) 1925 if (x86_pmu.check_microcode)
@@ -1955,7 +1949,6 @@ static struct pmu pmu = {
1955 .commit_txn = x86_pmu_commit_txn, 1949 .commit_txn = x86_pmu_commit_txn,
1956 1950
1957 .event_idx = x86_pmu_event_idx, 1951 .event_idx = x86_pmu_event_idx,
1958 .flush_branch_stack = x86_pmu_flush_branch_stack,
1959 .sched_task = x86_pmu_sched_task, 1952 .sched_task = x86_pmu_sched_task,
1960}; 1953};
1961 1954
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 211b54c0c00c..949d0083a29e 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -472,7 +472,6 @@ struct x86_pmu {
472 void (*cpu_dead)(int cpu); 472 void (*cpu_dead)(int cpu);
473 473
474 void (*check_microcode)(void); 474 void (*check_microcode)(void);
475 void (*flush_branch_stack)(void);
476 void (*sched_task)(struct perf_event_context *ctx, 475 void (*sched_task)(struct perf_event_context *ctx,
477 bool sched_in); 476 bool sched_in);
478 477
@@ -733,6 +732,8 @@ void intel_pmu_pebs_disable_all(void);
733 732
734void intel_ds_init(void); 733void intel_ds_init(void);
735 734
735void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in);
736
736void intel_pmu_lbr_reset(void); 737void intel_pmu_lbr_reset(void);
737 738
738void intel_pmu_lbr_enable(struct perf_event *event); 739void intel_pmu_lbr_enable(struct perf_event *event);
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 498b6d967138..424fbf74dee7 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -2044,18 +2044,6 @@ static void intel_pmu_cpu_dying(int cpu)
2044 fini_debug_store_on_cpu(cpu); 2044 fini_debug_store_on_cpu(cpu);
2045} 2045}
2046 2046
2047static void intel_pmu_flush_branch_stack(void)
2048{
2049 /*
2050 * Intel LBR does not tag entries with the
2051 * PID of the current task, then we need to
2052 * flush it on ctxsw
2053 * For now, we simply reset it
2054 */
2055 if (x86_pmu.lbr_nr)
2056 intel_pmu_lbr_reset();
2057}
2058
2059PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63"); 2047PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
2060 2048
2061PMU_FORMAT_ATTR(ldlat, "config1:0-15"); 2049PMU_FORMAT_ATTR(ldlat, "config1:0-15");
@@ -2107,7 +2095,7 @@ static __initconst const struct x86_pmu intel_pmu = {
2107 .cpu_starting = intel_pmu_cpu_starting, 2095 .cpu_starting = intel_pmu_cpu_starting,
2108 .cpu_dying = intel_pmu_cpu_dying, 2096 .cpu_dying = intel_pmu_cpu_dying,
2109 .guest_get_msrs = intel_guest_get_msrs, 2097 .guest_get_msrs = intel_guest_get_msrs,
2110 .flush_branch_stack = intel_pmu_flush_branch_stack, 2098 .sched_task = intel_pmu_lbr_sched_task,
2111}; 2099};
2112 2100
2113static __init void intel_clovertown_quirk(void) 2101static __init void intel_clovertown_quirk(void)
diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
index 8bc078f43a82..c0e23c5f85bb 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
@@ -177,6 +177,31 @@ void intel_pmu_lbr_reset(void)
177 intel_pmu_lbr_reset_64(); 177 intel_pmu_lbr_reset_64();
178} 178}
179 179
180void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in)
181{
182 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
183
184 if (!x86_pmu.lbr_nr)
185 return;
186
187 /*
188 * When sampling the branck stack in system-wide, it may be
189 * necessary to flush the stack on context switch. This happens
190 * when the branch stack does not tag its entries with the pid
191 * of the current task. Otherwise it becomes impossible to
192 * associate a branch entry with a task. This ambiguity is more
193 * likely to appear when the branch stack supports priv level
194 * filtering and the user sets it to monitor only at the user
195 * level (which could be a useful measurement in system-wide
196 * mode). In that case, the risk is high of having a branch
197 * stack with branch from multiple tasks.
198 */
199 if (sched_in) {
200 intel_pmu_lbr_reset();
201 cpuc->lbr_context = ctx;
202 }
203}
204
180void intel_pmu_lbr_enable(struct perf_event *event) 205void intel_pmu_lbr_enable(struct perf_event *event)
181{ 206{
182 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); 207 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
@@ -195,6 +220,7 @@ void intel_pmu_lbr_enable(struct perf_event *event)
195 cpuc->br_sel = event->hw.branch_reg.reg; 220 cpuc->br_sel = event->hw.branch_reg.reg;
196 221
197 cpuc->lbr_users++; 222 cpuc->lbr_users++;
223 perf_sched_cb_inc(event->ctx->pmu);
198} 224}
199 225
200void intel_pmu_lbr_disable(struct perf_event *event) 226void intel_pmu_lbr_disable(struct perf_event *event)
@@ -206,6 +232,7 @@ void intel_pmu_lbr_disable(struct perf_event *event)
206 232
207 cpuc->lbr_users--; 233 cpuc->lbr_users--;
208 WARN_ON_ONCE(cpuc->lbr_users < 0); 234 WARN_ON_ONCE(cpuc->lbr_users < 0);
235 perf_sched_cb_dec(event->ctx->pmu);
209 236
210 if (cpuc->enabled && !cpuc->lbr_users) { 237 if (cpuc->enabled && !cpuc->lbr_users) {
211 __intel_pmu_lbr_disable(); 238 __intel_pmu_lbr_disable();