aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYan, Zheng <zheng.z.yan@intel.com>2014-11-04 21:55:58 -0500
committerIngo Molnar <mingo@kernel.org>2015-02-18 11:16:02 -0500
commitba532500c5651a4be4108acc64ed99a95cb005b3 (patch)
tree6fe0a328c1b461bea944dd4b1c9aa46fb71b0fd4
parent27ac905b8f88d28779b0661809286b5ba2817d37 (diff)
perf: Introduce pmu context switch callback
The callback is invoked when process is scheduled in or out. It provides mechanism for later patches to save/store the LBR stack. For the schedule in case, the callback is invoked at the same place that flush branch stack callback is invoked. So it also can replace the flush branch stack callback. To avoid unnecessary overhead, the callback is enabled only when there are events use the LBR stack. 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-3-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/kernel/cpu/perf_event.c7
-rw-r--r--arch/x86/kernel/cpu/perf_event.h2
-rw-r--r--include/linux/perf_event.h9
-rw-r--r--kernel/events/core.c57
4 files changed, 75 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index b71a7f86d68a..0efbd6cc2966 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1914,6 +1914,12 @@ static const struct attribute_group *x86_pmu_attr_groups[] = {
1914 NULL, 1914 NULL,
1915}; 1915};
1916 1916
1917static void x86_pmu_sched_task(struct perf_event_context *ctx, bool sched_in)
1918{
1919 if (x86_pmu.sched_task)
1920 x86_pmu.sched_task(ctx, sched_in);
1921}
1922
1917static void x86_pmu_flush_branch_stack(void) 1923static void x86_pmu_flush_branch_stack(void)
1918{ 1924{
1919 if (x86_pmu.flush_branch_stack) 1925 if (x86_pmu.flush_branch_stack)
@@ -1950,6 +1956,7 @@ static struct pmu pmu = {
1950 1956
1951 .event_idx = x86_pmu_event_idx, 1957 .event_idx = x86_pmu_event_idx,
1952 .flush_branch_stack = x86_pmu_flush_branch_stack, 1958 .flush_branch_stack = x86_pmu_flush_branch_stack,
1959 .sched_task = x86_pmu_sched_task,
1953}; 1960};
1954 1961
1955void arch_perf_update_userpage(struct perf_event *event, 1962void arch_perf_update_userpage(struct perf_event *event,
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 0c45b22495dc..211b54c0c00c 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -473,6 +473,8 @@ struct x86_pmu {
473 473
474 void (*check_microcode)(void); 474 void (*check_microcode)(void);
475 void (*flush_branch_stack)(void); 475 void (*flush_branch_stack)(void);
476 void (*sched_task)(struct perf_event_context *ctx,
477 bool sched_in);
476 478
477 /* 479 /*
478 * Intel Arch Perfmon v2+ 480 * Intel Arch Perfmon v2+
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 33262004c310..fbab6235d053 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -265,6 +265,13 @@ struct pmu {
265 * flush branch stack on context-switches (needed in cpu-wide mode) 265 * flush branch stack on context-switches (needed in cpu-wide mode)
266 */ 266 */
267 void (*flush_branch_stack) (void); 267 void (*flush_branch_stack) (void);
268
269 /*
270 * context-switches callback
271 */
272 void (*sched_task) (struct perf_event_context *ctx,
273 bool sched_in);
274
268}; 275};
269 276
270/** 277/**
@@ -558,6 +565,8 @@ extern void perf_event_delayed_put(struct task_struct *task);
558extern void perf_event_print_debug(void); 565extern void perf_event_print_debug(void);
559extern void perf_pmu_disable(struct pmu *pmu); 566extern void perf_pmu_disable(struct pmu *pmu);
560extern void perf_pmu_enable(struct pmu *pmu); 567extern void perf_pmu_enable(struct pmu *pmu);
568extern void perf_sched_cb_dec(struct pmu *pmu);
569extern void perf_sched_cb_inc(struct pmu *pmu);
561extern int perf_event_task_disable(void); 570extern int perf_event_task_disable(void);
562extern int perf_event_task_enable(void); 571extern int perf_event_task_enable(void);
563extern int perf_event_refresh(struct perf_event *event, int refresh); 572extern int perf_event_refresh(struct perf_event *event, int refresh);
diff --git a/kernel/events/core.c b/kernel/events/core.c
index fef45b4bb5f8..6c8b31b7efb6 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -154,6 +154,7 @@ enum event_type_t {
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); 156static DEFINE_PER_CPU(atomic_t, perf_branch_stack_events);
157static DEFINE_PER_CPU(int, perf_sched_cb_usages);
157 158
158static atomic_t nr_mmap_events __read_mostly; 159static atomic_t nr_mmap_events __read_mostly;
159static atomic_t nr_comm_events __read_mostly; 160static atomic_t nr_comm_events __read_mostly;
@@ -2577,6 +2578,56 @@ unlock:
2577 } 2578 }
2578} 2579}
2579 2580
2581void perf_sched_cb_dec(struct pmu *pmu)
2582{
2583 this_cpu_dec(perf_sched_cb_usages);
2584}
2585
2586void perf_sched_cb_inc(struct pmu *pmu)
2587{
2588 this_cpu_inc(perf_sched_cb_usages);
2589}
2590
2591/*
2592 * This function provides the context switch callback to the lower code
2593 * layer. It is invoked ONLY when the context switch callback is enabled.
2594 */
2595static void perf_pmu_sched_task(struct task_struct *prev,
2596 struct task_struct *next,
2597 bool sched_in)
2598{
2599 struct perf_cpu_context *cpuctx;
2600 struct pmu *pmu;
2601 unsigned long flags;
2602
2603 if (prev == next)
2604 return;
2605
2606 local_irq_save(flags);
2607
2608 rcu_read_lock();
2609
2610 list_for_each_entry_rcu(pmu, &pmus, entry) {
2611 if (pmu->sched_task) {
2612 cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
2613
2614 perf_ctx_lock(cpuctx, cpuctx->task_ctx);
2615
2616 perf_pmu_disable(pmu);
2617
2618 pmu->sched_task(cpuctx->task_ctx, sched_in);
2619
2620 perf_pmu_enable(pmu);
2621
2622 perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
2623 }
2624 }
2625
2626 rcu_read_unlock();
2627
2628 local_irq_restore(flags);
2629}
2630
2580#define for_each_task_context_nr(ctxn) \ 2631#define for_each_task_context_nr(ctxn) \
2581 for ((ctxn) = 0; (ctxn) < perf_nr_task_contexts; (ctxn)++) 2632 for ((ctxn) = 0; (ctxn) < perf_nr_task_contexts; (ctxn)++)
2582 2633
@@ -2596,6 +2647,9 @@ void __perf_event_task_sched_out(struct task_struct *task,
2596{ 2647{
2597 int ctxn; 2648 int ctxn;
2598 2649
2650 if (__this_cpu_read(perf_sched_cb_usages))
2651 perf_pmu_sched_task(task, next, false);
2652
2599 for_each_task_context_nr(ctxn) 2653 for_each_task_context_nr(ctxn)
2600 perf_event_context_sched_out(task, ctxn, next); 2654 perf_event_context_sched_out(task, ctxn, next);
2601 2655
@@ -2847,6 +2901,9 @@ void __perf_event_task_sched_in(struct task_struct *prev,
2847 /* check for system-wide branch_stack events */ 2901 /* check for system-wide branch_stack events */
2848 if (atomic_read(this_cpu_ptr(&perf_branch_stack_events))) 2902 if (atomic_read(this_cpu_ptr(&perf_branch_stack_events)))
2849 perf_branch_stack_sched_in(prev, task); 2903 perf_branch_stack_sched_in(prev, task);
2904
2905 if (__this_cpu_read(perf_sched_cb_usages))
2906 perf_pmu_sched_task(prev, task, true);
2850} 2907}
2851 2908
2852static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count) 2909static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)