|
@@ -154,6 +154,7 @@ enum event_type_t {
|
|
struct static_key_deferred perf_sched_events __read_mostly;
|
|
struct static_key_deferred perf_sched_events __read_mostly;
|
|
static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
|
|
static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
|
|
static DEFINE_PER_CPU(atomic_t, perf_branch_stack_events);
|
|
static DEFINE_PER_CPU(atomic_t, perf_branch_stack_events);
|
|
|
|
+static DEFINE_PER_CPU(int, perf_sched_cb_usages);
|
|
|
|
|
|
static atomic_t nr_mmap_events __read_mostly;
|
|
static atomic_t nr_mmap_events __read_mostly;
|
|
static atomic_t nr_comm_events __read_mostly;
|
|
static atomic_t nr_comm_events __read_mostly;
|
|
@@ -2577,6 +2578,56 @@ unlock:
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void perf_sched_cb_dec(struct pmu *pmu)
|
|
|
|
+{
|
|
|
|
+ this_cpu_dec(perf_sched_cb_usages);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void perf_sched_cb_inc(struct pmu *pmu)
|
|
|
|
+{
|
|
|
|
+ this_cpu_inc(perf_sched_cb_usages);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * This function provides the context switch callback to the lower code
|
|
|
|
+ * layer. It is invoked ONLY when the context switch callback is enabled.
|
|
|
|
+ */
|
|
|
|
+static void perf_pmu_sched_task(struct task_struct *prev,
|
|
|
|
+ struct task_struct *next,
|
|
|
|
+ bool sched_in)
|
|
|
|
+{
|
|
|
|
+ struct perf_cpu_context *cpuctx;
|
|
|
|
+ struct pmu *pmu;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+
|
|
|
|
+ if (prev == next)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ local_irq_save(flags);
|
|
|
|
+
|
|
|
|
+ rcu_read_lock();
|
|
|
|
+
|
|
|
|
+ list_for_each_entry_rcu(pmu, &pmus, entry) {
|
|
|
|
+ if (pmu->sched_task) {
|
|
|
|
+ cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
|
|
|
|
+
|
|
|
|
+ perf_ctx_lock(cpuctx, cpuctx->task_ctx);
|
|
|
|
+
|
|
|
|
+ perf_pmu_disable(pmu);
|
|
|
|
+
|
|
|
|
+ pmu->sched_task(cpuctx->task_ctx, sched_in);
|
|
|
|
+
|
|
|
|
+ perf_pmu_enable(pmu);
|
|
|
|
+
|
|
|
|
+ perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rcu_read_unlock();
|
|
|
|
+
|
|
|
|
+ local_irq_restore(flags);
|
|
|
|
+}
|
|
|
|
+
|
|
#define for_each_task_context_nr(ctxn) \
|
|
#define for_each_task_context_nr(ctxn) \
|
|
for ((ctxn) = 0; (ctxn) < perf_nr_task_contexts; (ctxn)++)
|
|
for ((ctxn) = 0; (ctxn) < perf_nr_task_contexts; (ctxn)++)
|
|
|
|
|
|
@@ -2596,6 +2647,9 @@ void __perf_event_task_sched_out(struct task_struct *task,
|
|
{
|
|
{
|
|
int ctxn;
|
|
int ctxn;
|
|
|
|
|
|
|
|
+ if (__this_cpu_read(perf_sched_cb_usages))
|
|
|
|
+ perf_pmu_sched_task(task, next, false);
|
|
|
|
+
|
|
for_each_task_context_nr(ctxn)
|
|
for_each_task_context_nr(ctxn)
|
|
perf_event_context_sched_out(task, ctxn, next);
|
|
perf_event_context_sched_out(task, ctxn, next);
|
|
|
|
|
|
@@ -2847,6 +2901,9 @@ void __perf_event_task_sched_in(struct task_struct *prev,
|
|
/* check for system-wide branch_stack events */
|
|
/* check for system-wide branch_stack events */
|
|
if (atomic_read(this_cpu_ptr(&perf_branch_stack_events)))
|
|
if (atomic_read(this_cpu_ptr(&perf_branch_stack_events)))
|
|
perf_branch_stack_sched_in(prev, task);
|
|
perf_branch_stack_sched_in(prev, task);
|
|
|
|
+
|
|
|
|
+ if (__this_cpu_read(perf_sched_cb_usages))
|
|
|
|
+ perf_pmu_sched_task(prev, task, true);
|
|
}
|
|
}
|
|
|
|
|
|
static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
|
|
static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
|