aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--include/linux/perf_event.h1
-rw-r--r--kernel/events/core.c77
6 files changed, 30 insertions, 99 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();
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index fbab6235d053..c7007a564440 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -511,7 +511,6 @@ struct perf_event_context {
511 u64 generation; 511 u64 generation;
512 int pin_count; 512 int pin_count;
513 int nr_cgroups; /* cgroup evts */ 513 int nr_cgroups; /* cgroup evts */
514 int nr_branch_stack; /* branch_stack evt */
515 struct rcu_head rcu_head; 514 struct rcu_head rcu_head;
516 515
517 struct delayed_work orphans_remove; 516 struct delayed_work orphans_remove;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 6c8b31b7efb6..f563ce767f93 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -153,7 +153,6 @@ enum event_type_t {
153 */ 153 */
154struct static_key_deferred perf_sched_events __read_mostly; 154struct static_key_deferred perf_sched_events __read_mostly;
155static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); 155static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
156static DEFINE_PER_CPU(atomic_t, perf_branch_stack_events);
157static DEFINE_PER_CPU(int, perf_sched_cb_usages); 156static DEFINE_PER_CPU(int, perf_sched_cb_usages);
158 157
159static atomic_t nr_mmap_events __read_mostly; 158static atomic_t nr_mmap_events __read_mostly;
@@ -1240,9 +1239,6 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
1240 if (is_cgroup_event(event)) 1239 if (is_cgroup_event(event))
1241 ctx->nr_cgroups++; 1240 ctx->nr_cgroups++;
1242 1241
1243 if (has_branch_stack(event))
1244 ctx->nr_branch_stack++;
1245
1246 list_add_rcu(&event->event_entry, &ctx->event_list); 1242 list_add_rcu(&event->event_entry, &ctx->event_list);
1247 ctx->nr_events++; 1243 ctx->nr_events++;
1248 if (event->attr.inherit_stat) 1244 if (event->attr.inherit_stat)
@@ -1409,9 +1405,6 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
1409 cpuctx->cgrp = NULL; 1405 cpuctx->cgrp = NULL;
1410 } 1406 }
1411 1407
1412 if (has_branch_stack(event))
1413 ctx->nr_branch_stack--;
1414
1415 ctx->nr_events--; 1408 ctx->nr_events--;
1416 if (event->attr.inherit_stat) 1409 if (event->attr.inherit_stat)
1417 ctx->nr_stat--; 1410 ctx->nr_stat--;
@@ -2809,64 +2802,6 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx,
2809} 2802}
2810 2803
2811/* 2804/*
2812 * When sampling the branck stack in system-wide, it may be necessary
2813 * to flush the stack on context switch. This happens when the branch
2814 * stack does not tag its entries with the pid of the current task.
2815 * Otherwise it becomes impossible to associate a branch entry with a
2816 * task. This ambiguity is more likely to appear when the branch stack
2817 * supports priv level filtering and the user sets it to monitor only
2818 * at the user level (which could be a useful measurement in system-wide
2819 * mode). In that case, the risk is high of having a branch stack with
2820 * branch from multiple tasks. Flushing may mean dropping the existing
2821 * entries or stashing them somewhere in the PMU specific code layer.
2822 *
2823 * This function provides the context switch callback to the lower code
2824 * layer. It is invoked ONLY when there is at least one system-wide context
2825 * with at least one active event using taken branch sampling.
2826 */
2827static void perf_branch_stack_sched_in(struct task_struct *prev,
2828 struct task_struct *task)
2829{
2830 struct perf_cpu_context *cpuctx;
2831 struct pmu *pmu;
2832 unsigned long flags;
2833
2834 /* no need to flush branch stack if not changing task */
2835 if (prev == task)
2836 return;
2837
2838 local_irq_save(flags);
2839
2840 rcu_read_lock();
2841
2842 list_for_each_entry_rcu(pmu, &pmus, entry) {
2843 cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
2844
2845 /*
2846 * check if the context has at least one
2847 * event using PERF_SAMPLE_BRANCH_STACK
2848 */
2849 if (cpuctx->ctx.nr_branch_stack > 0
2850 && pmu->flush_branch_stack) {
2851
2852 perf_ctx_lock(cpuctx, cpuctx->task_ctx);
2853
2854 perf_pmu_disable(pmu);
2855
2856 pmu->flush_branch_stack();
2857
2858 perf_pmu_enable(pmu);
2859
2860 perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
2861 }
2862 }
2863
2864 rcu_read_unlock();
2865
2866 local_irq_restore(flags);
2867}
2868
2869/*
2870 * Called from scheduler to add the events of the current task 2805 * Called from scheduler to add the events of the current task
2871 * with interrupts disabled. 2806 * with interrupts disabled.
2872 * 2807 *
@@ -2898,10 +2833,6 @@ void __perf_event_task_sched_in(struct task_struct *prev,
2898 if (atomic_read(this_cpu_ptr(&perf_cgroup_events))) 2833 if (atomic_read(this_cpu_ptr(&perf_cgroup_events)))
2899 perf_cgroup_sched_in(prev, task); 2834 perf_cgroup_sched_in(prev, task);
2900 2835
2901 /* check for system-wide branch_stack events */
2902 if (atomic_read(this_cpu_ptr(&perf_branch_stack_events)))
2903 perf_branch_stack_sched_in(prev, task);
2904
2905 if (__this_cpu_read(perf_sched_cb_usages)) 2836 if (__this_cpu_read(perf_sched_cb_usages))
2906 perf_pmu_sched_task(prev, task, true); 2837 perf_pmu_sched_task(prev, task, true);
2907} 2838}
@@ -3480,10 +3411,6 @@ static void unaccount_event_cpu(struct perf_event *event, int cpu)
3480 if (event->parent) 3411 if (event->parent)
3481 return; 3412 return;
3482 3413
3483 if (has_branch_stack(event)) {
3484 if (!(event->attach_state & PERF_ATTACH_TASK))
3485 atomic_dec(&per_cpu(perf_branch_stack_events, cpu));
3486 }
3487 if (is_cgroup_event(event)) 3414 if (is_cgroup_event(event))
3488 atomic_dec(&per_cpu(perf_cgroup_events, cpu)); 3415 atomic_dec(&per_cpu(perf_cgroup_events, cpu));
3489} 3416}
@@ -7139,10 +7066,6 @@ static void account_event_cpu(struct perf_event *event, int cpu)
7139 if (event->parent) 7066 if (event->parent)
7140 return; 7067 return;
7141 7068
7142 if (has_branch_stack(event)) {
7143 if (!(event->attach_state & PERF_ATTACH_TASK))
7144 atomic_inc(&per_cpu(perf_branch_stack_events, cpu));
7145 }
7146 if (is_cgroup_event(event)) 7069 if (is_cgroup_event(event))
7147 atomic_inc(&per_cpu(perf_cgroup_events, cpu)); 7070 atomic_inc(&per_cpu(perf_cgroup_events, cpu));
7148} 7071}