diff options
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 7 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.h | 3 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel.c | 14 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_lbr.c | 27 | ||||
-rw-r--r-- | include/linux/perf_event.h | 1 | ||||
-rw-r--r-- | kernel/events/core.c | 77 |
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 | ||
1923 | static void x86_pmu_flush_branch_stack(void) | ||
1924 | { | ||
1925 | if (x86_pmu.flush_branch_stack) | ||
1926 | x86_pmu.flush_branch_stack(); | ||
1927 | } | ||
1928 | |||
1929 | void perf_check_microcode(void) | 1923 | void 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 | ||
734 | void intel_ds_init(void); | 733 | void intel_ds_init(void); |
735 | 734 | ||
735 | void intel_pmu_lbr_sched_task(struct perf_event_context *ctx, bool sched_in); | ||
736 | |||
736 | void intel_pmu_lbr_reset(void); | 737 | void intel_pmu_lbr_reset(void); |
737 | 738 | ||
738 | void intel_pmu_lbr_enable(struct perf_event *event); | 739 | void 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 | ||
2047 | static 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 | |||
2059 | PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63"); | 2047 | PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63"); |
2060 | 2048 | ||
2061 | PMU_FORMAT_ATTR(ldlat, "config1:0-15"); | 2049 | PMU_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 | ||
2113 | static __init void intel_clovertown_quirk(void) | 2101 | static __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 | ||
180 | void 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 | |||
180 | void intel_pmu_lbr_enable(struct perf_event *event) | 205 | void 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 | ||
200 | void intel_pmu_lbr_disable(struct perf_event *event) | 226 | void 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 | */ |
154 | struct static_key_deferred perf_sched_events __read_mostly; | 154 | struct static_key_deferred perf_sched_events __read_mostly; |
155 | static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); | 155 | static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); |
156 | static DEFINE_PER_CPU(atomic_t, perf_branch_stack_events); | ||
157 | static DEFINE_PER_CPU(int, perf_sched_cb_usages); | 156 | static DEFINE_PER_CPU(int, perf_sched_cb_usages); |
158 | 157 | ||
159 | static atomic_t nr_mmap_events __read_mostly; | 158 | static 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 | */ | ||
2827 | static 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 | } |