Skip to contentSkip to conversation

Optimize cgroup ctx switch and remove cpuctx->unique_pmu

PATCH In review David Carrillo-Cisneros 4 participants 9 messages Jan 18, 2017 – Jan 30, 2017 perf events

lore
Share & tools
lore
#0 lore raw

v2 cover Optimize cgroup ctx switch and remove cpuctx->unique_pmu

v2: Rename local variable, as suggested by Mark Rutland and
add his Acked-by.
First patch is a resend of ("perf/core: Make cgroup switch visit only cpuctxs with cgroup events") with updated change log.

Second patch cleans up the now unused cpuctx->unique_pmu.

David Carrillo-Cisneros (2):
perf/core: Make cgroup switch visit only cpuctxs with cgroup events perf/core: Remove perf_cpu_context::unique_pmu

 include/linux/perf_event.h |   2 +-
 kernel/events/core.c       | 129 ++++++++++++++++-----------------------------
 2 files changed, 47 insertions(+), 84 deletions(-)
Signature · 1 line
2.11.0.483.g087da7b7c-goog
#1 lore raw

PATCH v2 1/2 perf/core: Make cgroup switch visit only cpuctxs with cgroup events

v2: Rename local variable as suggested by Mark Rutland.
v1: This is a resend of v2 of ("perf/core: only check cpuctx with cgroup
events during cgroup switch") with updated changelog.

This patch follows from a conversation in CQM/CMT's last series about speeding up the context switch for cgroup events:

https://patchwork.kernel.org/patch/9478617/

This is a low-hanging fruit optimization. It replaces the iteration over the "pmus" list in cgroup switch by an iteration over a new list that contains only cpuctxs with at least one cgroup event.

This is necessary because the number of pmus have increased over the years e.g modern x86 server systems have well above 50 pmus.
The iteration over the full pmu list is unneccessary and can be costly in heavy cache contention scenarios.

Below are some instrumentation measurements with 10, 50 and 90 percentiles of the total cost of context switch before and after this optimization for a simple array read/write microbenchark.

Contention
Level Nr events Before (us) After (us) Median
L2 L3 types (10%, 50%, 90%) (10%, 50%, 90% Speedup
--------------------------------------------------------------------------

Low   Low       1       (1.72, 2.42, 5.85)    (1.35, 1.64, 5.46)     29%
High  Low       1       (2.08, 4.56, 19.8)    (1720, 2.20, 13.7)     51%
High  High      1       (2.86, 10.4, 12.7)    (2.54, 4.32, 12.1)     58%
Low   Low       2       (1.98, 3.20, 6.89)    (1.68, 2.41, 8.89)     24%
High  Low       2       (2.48, 5.28, 22.4)    (2150, 3.69, 14.6)     30%
High  High      2       (3.32, 8.09, 13.9)    (2.80, 5.15, 13.7)     36%

where:
1 event type = cycles
2 event types = cycles,intel_cqm/llc_occupancy/

Contention L2 Low: workset < L2 cache size.

              High:  "     >>  L2   "     " .

Contention L3 Low: workset of task on all sockets < L3 cache size.
High: " " " " " " >> L3 " " .

Median Speedup is (50%ile Before - 50%ile After) / 50%ile Before

Unsurprisingly, the benefits of this optimization decrease with the number of cpuctxs with a cgroup events, yet, is never detrimental.

---
 include/linux/perf_event.h |  1 +
 kernel/events/core.c       | 98 +++++++++++++++++++++-------------------------
 2 files changed, 46 insertions(+), 53 deletions(-)
include/linux/perf_event.h +1 -0
index 4741ecdb9817..10d223572855 100644
@@ -788,6 +788,7 @@ struct perf_cpu_context {
 	struct pmu			*unique_pmu;
 #ifdef CONFIG_CGROUP_PERF
 	struct perf_cgroup		*cgrp;
+	struct list_head		cgrp_cpuctx_entry;
 #endif
 
 	struct list_head		sched_cb_entry;
kernel/events/core.c +45 -53

139 lines not on this page · raw message

Signature · 1 line
2.11.0.483.g087da7b7c-goog
#2 lore raw

[tip:perf/core] perf/core: Make cgroup switch visit only cpuctxs with cgroup events

perf/core: Make cgroup switch visit only cpuctxs with cgroup events
Commit-ID:  058fe1c0440e68a1ba3c2270ae43e9f0298b27d8
Gitweb:     http://git.kernel.org/tip/058fe1c0440e68a1ba3c2270ae43e9f0298b27d8
Author:     David Carrillo-Cisneros <[email protected]>
AuthorDate: Wed, 18 Jan 2017 11:24:53 -0800
Committer:  Ingo Molnar <[email protected]>
CommitDate: Mon, 30 Jan 2017 12:01:13 +0100

perf/core: Make cgroup switch visit only cpuctxs with cgroup events

This patch follows from a conversation in CQM/CMT's last series about speeding up the context switch for cgroup events:

https://patchwork.kernel.org/patch/9478617/

This is a low-hanging fruit optimization. It replaces the iteration over the "pmus" list in cgroup switch by an iteration over a new list that contains only cpuctxs with at least one cgroup event.

This is necessary because the number of PMUs have increased over the years e.g modern x86 server systems have well above 50 PMUs.

The iteration over the full PMU list is unneccessary and can be costly in heavy cache contention scenarios.

Below are some instrumentation measurements with 10, 50 and 90 percentiles of the total cost of context switch before and after this optimization for a simple array read/write microbenchark.

Contention
Level Nr events Before (us) After (us) Median
L2 L3 types (10%, 50%, 90%) (10%, 50%, 90% Speedup
--------------------------------------------------------------------------

  Low   Low       1       (1.72, 2.42, 5.85)    (1.35, 1.64, 5.46)     29%
  High  Low       1       (2.08, 4.56, 19.8)    (1720, 2.20, 13.7)     51%
  High  High      1       (2.86, 10.4, 12.7)    (2.54, 4.32, 12.1)     58%
  Low   Low       2       (1.98, 3.20, 6.89)    (1.68, 2.41, 8.89)     24%
  High  Low       2       (2.48, 5.28, 22.4)    (2150, 3.69, 14.6)     30%
  High  High      2       (3.32, 8.09, 13.9)    (2.80, 5.15, 13.7)     36%

where:

1 event type = cycles
2 event types = cycles,intel_cqm/llc_occupancy/

Contention L2 Low: workset < L2 cache size.

                 High:  "     >>  L2   "     " .

Contention L3 Low: workset of task on all sockets < L3 cache size.
High: " " " " " " >> L3 " " .

Median Speedup is (50%ile Before - 50%ile After) / 50%ile Before

Unsurprisingly, the benefits of this optimization decrease with the number of cpuctxs with a cgroup events, yet, is never detrimental.

Cc Alexander Shishkin <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Kan Liang <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Paul Turner <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Srinivas Pandruvada <[email protected]>
Cc Stephane Eranian <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Vikas Shivappa <[email protected]>
Cc Vince Weaver <[email protected]>
Cc Vince Weaver <[email protected]>
---
 include/linux/perf_event.h |  1 +
 kernel/events/core.c       | 98 +++++++++++++++++++++-------------------------
 2 files changed, 46 insertions(+), 53 deletions(-)
include/linux/perf_event.h +1 -0
index 78ed810..dfa7257 100644
@@ -788,6 +788,7 @@ struct perf_cpu_context {
 	struct pmu			*unique_pmu;
 #ifdef CONFIG_CGROUP_PERF
 	struct perf_cgroup		*cgrp;
+	struct list_head		cgrp_cpuctx_entry;
 #endif
 
 	struct list_head		sched_cb_entry;
kernel/events/core.c +45 -53

139 lines not on this page · raw message

#3 lore raw

PATCH v2 2/2 perf/core: Remove perf_cpu_context::unique_pmu

In reply to David Carrillo-Cisneros

cpuctx->unique_pmu was originally introduced as a way to identify cpuctxs with shared pmus in order to avoid visiting the same cpuctx more than once in a for_each_pmu loop.

cpuctx->unique_pmu == cpuctx->pmu in non-software task contexts since they have only one pmu per cpuctx. Since perf_pmu_sched_task is only called in hw contexts, this patch replaces cpuctx->unique_pmu by cpuctx->pmu in it.

The change above, together with the previous patch in this series, removed the remaining uses of cpuctx->unique_pmu, so we remove it altogether.

---
 include/linux/perf_event.h |  1 -
 kernel/events/core.c       | 31 +------------------------------
 2 files changed, 1 insertion(+), 31 deletions(-)
include/linux/perf_event.h +0 -1
index 10d223572855..4f8a1f681aac 100644
@@ -785,7 +785,6 @@ struct perf_cpu_context {
 	ktime_t				hrtimer_interval;
 	unsigned int			hrtimer_active;
 
-	struct pmu			*unique_pmu;
 #ifdef CONFIG_CGROUP_PERF
 	struct perf_cgroup		*cgrp;
 	struct list_head		cgrp_cpuctx_entry;
kernel/events/core.c +1 -30
index 5f5b760bc25b..65b706d25422 100644
@@ -2883,7 +2883,7 @@ static void perf_pmu_sched_task(struct task_struct *prev,
 		return;
 
 	list_for_each_entry(cpuctx, this_cpu_ptr(&sched_cb_list), sched_cb_entry) {
-		pmu = cpuctx->unique_pmu; /* software PMUs will not have sched_task */
+		pmu = cpuctx->ctx.pmu; /* software PMUs will not have sched_task */
 
 		if (WARN_ON_ONCE(!pmu->sched_task))
 			continue;
@@ -8572,37 +8572,10 @@ static struct perf_cpu_context __percpu *find_pmu_context(int ctxn)
 	return NULL;
 }
 
-static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu)
-{
-	int cpu;
-
-	for_each_possible_cpu(cpu) {
-		struct perf_cpu_context *cpuctx;
-
-		cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
-
-		if (cpuctx->unique_pmu == old_pmu)
-			cpuctx->unique_pmu = pmu;
-	}
-}
-
 static void free_pmu_context(struct pmu *pmu)
 {
-	struct pmu *i;
-
 	mutex_lock(&pmus_lock);
-	/*
-	 * Like a real lame refcount.
-	 */
-	list_for_each_entry(i, &pmus, entry) {
-		if (i->pmu_cpu_context == pmu->pmu_cpu_context) {
-			update_pmu_context(i, pmu);
-			goto out;
-		}
-	}
-
 	free_percpu(pmu->pmu_cpu_context);
-out:
 	mutex_unlock(&pmus_lock);
 }
 
@@ -8806,8 +8779,6 @@ int perf_pmu_register(struct pmu *pmu, const char *name, int type)
 		cpuctx->ctx.pmu = pmu;
 
 		__perf_mux_hrtimer_init(cpuctx, cpu);
-
-		cpuctx->unique_pmu = pmu;
 	}
 
 got_cpu_context:
Signature · 1 line
2.11.0.483.g087da7b7c-goog
maintainer
#4 lore raw

Re: [PATCH v2 2/2] perf/core: Remove perf_cpu_context::unique_pmu

Quoted 42 lines · David Carrillo-Cisneros

cpuctx->unique_pmu was originally introduced as a way to identify cpuctxs with shared pmus in order to avoid visiting the same cpuctx more than once in a for_each_pmu loop.

cpuctx->unique_pmu == cpuctx->pmu in non-software task contexts since they have only one pmu per cpuctx. Since perf_pmu_sched_task is only called in hw contexts, this patch replaces cpuctx->unique_pmu by cpuctx->pmu in it.

The change above, together with the previous patch in this series, removed the remaining uses of cpuctx->unique_pmu, so we remove it altogether.

kernel/events/core.c +0 -20
@@ -8572,37 +8572,10 @@ static struct perf_cpu_context __percpu *find_pmu_context(int ctxn)
 	return NULL;
 }
 
-static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu)
-{
-	int cpu;
-
-	for_each_possible_cpu(cpu) {
-		struct perf_cpu_context *cpuctx;
-
-		cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
-
-		if (cpuctx->unique_pmu == old_pmu)
-			cpuctx->unique_pmu = pmu;
-	}
-}
-
 static void free_pmu_context(struct pmu *pmu)
 {
-	struct pmu *i;
-
 	mutex_lock(&pmus_lock);
-	/*
-	 * Like a real lame refcount.
-	 */
-	list_for_each_entry(i, &pmus, entry) {

kernel/events/core.c static struct perf_cpu_context __percpu *find_pmu_context(int ctxn) · line 8580

Quoted 10 lines
kernel/events/core.c +0 -7
-		if (i->pmu_cpu_context == pmu->pmu_cpu_context) {
-			update_pmu_context(i, pmu);
-			goto out;
-		}
-	}
-
 	free_percpu(pmu->pmu_cpu_context);
-out:
 	mutex_unlock(&pmus_lock);
 }

This very much relies on us never calling perf_pmu_unregister() on the software PMUs afaict. A condition not mention in the Changelog.

reviewer
#5 lore raw

Re: [PATCH v2 2/2] perf/core: Remove perf_cpu_context::unique_pmu

Quoted 47 lines · Peter Zijlstra
Quoted 46 lines · David Carrillo-Cisneros

cpuctx->unique_pmu was originally introduced as a way to identify cpuctxs with shared pmus in order to avoid visiting the same cpuctx more than once in a for_each_pmu loop.

cpuctx->unique_pmu == cpuctx->pmu in non-software task contexts since they have only one pmu per cpuctx. Since perf_pmu_sched_task is only called in hw contexts, this patch replaces cpuctx->unique_pmu by cpuctx->pmu in it.

The change above, together with the previous patch in this series, removed the remaining uses of cpuctx->unique_pmu, so we remove it altogether.

kernel/events/core.c +0 -25
@@ -8572,37 +8572,10 @@ static struct perf_cpu_context __percpu *find_pmu_context(int ctxn)
 	return NULL;
 }
 
-static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu)
-{
-	int cpu;
-
-	for_each_possible_cpu(cpu) {
-		struct perf_cpu_context *cpuctx;
-
-		cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
-
-		if (cpuctx->unique_pmu == old_pmu)
-			cpuctx->unique_pmu = pmu;
-	}
-}
-
 static void free_pmu_context(struct pmu *pmu)
 {
-	struct pmu *i;
-
 	mutex_lock(&pmus_lock);
-	/*
-	 * Like a real lame refcount.
-	 */
-	list_for_each_entry(i, &pmus, entry) {
-		if (i->pmu_cpu_context == pmu->pmu_cpu_context) {
-			update_pmu_context(i, pmu);
-			goto out;
-		}
-	}
Quoted 8 lines

kernel/events/core.c static struct perf_cpu_context __percpu *find_pmu_context(int ctxn) · line 8580

Quoted 5 lines
kernel/events/core.c +0 -2
-
 	free_percpu(pmu->pmu_cpu_context);
-out:
 	mutex_unlock(&pmus_lock);
 }

This very much relies on us never calling perf_pmu_unregister() on the software PMUs afaict. A condition not mention in the Changelog.

Ah; I did not consider that that could leave perf_pmu_sched_task() seeing a stale cpuctx->ctx.pmu.

That said, is this not already a problem elsewhere? We don't update ctx->pmu in perf_pmu_unregister, so this would be a problem for any path using ctx->pmu today (e.g. perf_event_context_sched_in()).

Thanks,
Mark.

#6 lore raw

Re: [PATCH v2 2/2] perf/core: Remove perf_cpu_context::unique_pmu

In reply to Peter Zijlstra
Quoted 48 lines · Peter Zijlstra
Quoted 47 lines · David Carrillo-Cisneros

cpuctx->unique_pmu was originally introduced as a way to identify cpuctxs with shared pmus in order to avoid visiting the same cpuctx more than once in a for_each_pmu loop.

cpuctx->unique_pmu == cpuctx->pmu in non-software task contexts since they have only one pmu per cpuctx. Since perf_pmu_sched_task is only called in hw contexts, this patch replaces cpuctx->unique_pmu by cpuctx->pmu in it.

The change above, together with the previous patch in this series, removed the remaining uses of cpuctx->unique_pmu, so we remove it altogether.

kernel/events/core.c +0 -25
@@ -8572,37 +8572,10 @@ static struct perf_cpu_context __percpu *find_pmu_context(int ctxn)
      return NULL;
 }
 
-static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu)
-{
-     int cpu;
-
-     for_each_possible_cpu(cpu) {
-             struct perf_cpu_context *cpuctx;
-
-             cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
-
-             if (cpuctx->unique_pmu == old_pmu)
-                     cpuctx->unique_pmu = pmu;
-     }
-}
-
 static void free_pmu_context(struct pmu *pmu)
 {
-     struct pmu *i;
-
      mutex_lock(&pmus_lock);
-     /*
-      * Like a real lame refcount.
-      */
-     list_for_each_entry(i, &pmus, entry) {
-             if (i->pmu_cpu_context == pmu->pmu_cpu_context) {
-                     update_pmu_context(i, pmu);
-                     goto out;
-             }
-     }
Quoted 9 lines

kernel/events/core.c static struct perf_cpu_context __percpu *find_pmu_context(int ctxn) · line 8580

Quoted 5 lines
kernel/events/core.c +0 -2
-
      free_percpu(pmu->pmu_cpu_context);
-out:
      mutex_unlock(&pmus_lock);
 }

This very much relies on us never calling perf_pmu_unregister() on the software PMUs afaict. A condition not mention in the Changelog.

What's a good way to solve this? Update the Changelog or add code to update ctx->pmu?

This issue would go away cleanly if we were to remove the context sharing across pmu's. Would you support work in that direction?

Thanks,
David

maintainer
#7 lore raw

Re: [PATCH v2 2/2] perf/core: Remove perf_cpu_context::unique_pmu

Quoted 18 lines · David Carrillo-Cisneros
Quoted 17 lines · Peter Zijlstra
Quoted 13 lines · David Carrillo-Cisneros

cpuctx->unique_pmu was originally introduced as a way to identify cpuctxs with shared pmus in order to avoid visiting the same cpuctx more than once in a for_each_pmu loop.

cpuctx->unique_pmu == cpuctx->pmu in non-software task contexts since they have only one pmu per cpuctx. Since perf_pmu_sched_task is only called in hw contexts, this patch replaces cpuctx->unique_pmu by cpuctx->pmu in it.

The change above, together with the previous patch in this series, removed the remaining uses of cpuctx->unique_pmu, so we remove it altogether.

Quoted 5 lines
Quoted 3 lines

This very much relies on us never calling perf_pmu_unregister() on the software PMUs afaict. A condition not mention in the Changelog.

What's a good way to solve this? Update the Changelog or add code to update ctx->pmu?

I think just update the Changelog and maybe put a comment near perf_pmu_register() and/or the sw pmu abuse that relies on this.

Quoted 2 lines

This issue would go away cleanly if we were to remove the context sharing across pmu's. Would you support work in that direction?

Its something that I've considered, the trivial solution is folding it all into the one swevent pmu by adding a switch in all the add/del/start/stop/read methods. Its a wee bit ugly but straight fwd.

I've not really found anything less ugly though; and I have to fully admit to the current situation being rather vile.

I also just found the below patch that I've had bitrotting since 2015.

---
Subject: perf: Move all software PMUs into their own file
From: Peter Zijlstra <[email protected]>
Date: Fri Apr 17 19:52:17 CEST 2015

---
 kernel/events/Makefile   |    2 
 kernel/events/core.c     | 1280 +++++------------------------------------------
 kernel/events/internal.h |   13 
 kernel/events/software.c | 1021 +++++++++++++++++++++++++++++++++++++
 4 files changed, 1184 insertions(+), 1132 deletions(-)
kernel/events/Makefile +1 -1
@@ -2,7 +2,7 @@ ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_core.o = $(CC_FLAGS_FTRACE)
 endif
 
-obj-y := core.o ring_buffer.o callchain.o
+obj-y := core.o software.o ring_buffer.o callchain.o
 
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_UPROBES) += uprobes.o
kernel/events/core.c +149 -1131

1,433 lines not on this page · raw message

kernel/events/internal.h +13 -0
@@ -228,4 +228,17 @@ static inline bool arch_perf_have_user_s
 #define perf_user_stack_pointer(regs) 0
 #endif /* CONFIG_HAVE_PERF_USER_STACK_DUMP */
 
+#define MAX_INTERRUPTS (~0ULL)
+
+extern int __perf_event_overflow(struct perf_event *event,
+			  int throttle, struct perf_sample_data *data,
+			  struct pt_regs *regs);
+
+extern void perf_event_free_filter(struct perf_event *event);
+extern void perf_event_free_bpf_prog(struct perf_event *event);
+extern int perf_event_set_filter(struct perf_event *event, void __user *arg);
+extern int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd);
+
+extern void perf_swevent_register(void);
+
 #endif /* _KERNEL_EVENTS_INTERNAL_H */
kernel/events/software.c new file +1021 -0

1,021 lines not on this page · raw message

#8 lore raw

[tip:perf/core] perf/core: Remove perf_cpu_context::unique_pmu

In reply to David Carrillo-Cisneros
perf/core: Remove perf_cpu_context::unique_pmu
Commit-ID:  1fd7e416995401ec082fc0fe6090a223969beda5
Gitweb:     http://git.kernel.org/tip/1fd7e416995401ec082fc0fe6090a223969beda5
Author:     David Carrillo-Cisneros <[email protected]>
AuthorDate: Wed, 18 Jan 2017 11:24:54 -0800
Committer:  Ingo Molnar <[email protected]>
CommitDate: Mon, 30 Jan 2017 12:01:14 +0100

perf/core: Remove perf_cpu_context::unique_pmu

cpuctx->unique_pmu was originally introduced as a way to identify cpuctxs with shared pmus in order to avoid visiting the same cpuctx more than once in a for_each_pmu loop.

cpuctx->unique_pmu == cpuctx->pmu in non-software task contexts since they have only one pmu per cpuctx. Since perf_pmu_sched_task() is only called in hw contexts, this patch replaces cpuctx->unique_pmu by cpuctx->pmu in it.

The change above, together with the previous patch in this series, removed the remaining uses of cpuctx->unique_pmu, so we remove it altogether.

Cc Alexander Shishkin <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Kan Liang <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Paul Turner <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Srinivas Pandruvada <[email protected]>
Cc Stephane Eranian <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Vikas Shivappa <[email protected]>
Cc Vince Weaver <[email protected]>
Cc Vince Weaver <[email protected]>
---
 include/linux/perf_event.h |  1 -
 kernel/events/core.c       | 31 +------------------------------
 2 files changed, 1 insertion(+), 31 deletions(-)
include/linux/perf_event.h +0 -1
index dfa7257..5c58e93 100644
@@ -785,7 +785,6 @@ struct perf_cpu_context {
 	ktime_t				hrtimer_interval;
 	unsigned int			hrtimer_active;
 
-	struct pmu			*unique_pmu;
 #ifdef CONFIG_CGROUP_PERF
 	struct perf_cgroup		*cgrp;
 	struct list_head		cgrp_cpuctx_entry;
kernel/events/core.c +1 -30
index 928a818..d92c7ad 100644
@@ -2932,7 +2932,7 @@ static void perf_pmu_sched_task(struct task_struct *prev,
 		return;
 
 	list_for_each_entry(cpuctx, this_cpu_ptr(&sched_cb_list), sched_cb_entry) {
-		pmu = cpuctx->unique_pmu; /* software PMUs will not have sched_task */
+		pmu = cpuctx->ctx.pmu; /* software PMUs will not have sched_task */
 
 		if (WARN_ON_ONCE(!pmu->sched_task))
 			continue;
@@ -8636,37 +8636,10 @@ static struct perf_cpu_context __percpu *find_pmu_context(int ctxn)
 	return NULL;
 }
 
-static void update_pmu_context(struct pmu *pmu, struct pmu *old_pmu)
-{
-	int cpu;
-
-	for_each_possible_cpu(cpu) {
-		struct perf_cpu_context *cpuctx;
-
-		cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
-
-		if (cpuctx->unique_pmu == old_pmu)
-			cpuctx->unique_pmu = pmu;
-	}
-}
-
 static void free_pmu_context(struct pmu *pmu)
 {
-	struct pmu *i;
-
 	mutex_lock(&pmus_lock);
-	/*
-	 * Like a real lame refcount.
-	 */
-	list_for_each_entry(i, &pmus, entry) {
-		if (i->pmu_cpu_context == pmu->pmu_cpu_context) {
-			update_pmu_context(i, pmu);
-			goto out;
-		}
-	}
-
 	free_percpu(pmu->pmu_cpu_context);
-out:
 	mutex_unlock(&pmus_lock);
 }
 
@@ -8870,8 +8843,6 @@ skip_type:
 		cpuctx->ctx.pmu = pmu;
 
 		__perf_mux_hrtimer_init(cpuctx, cpu);
-
-		cpuctx->unique_pmu = pmu;
 	}
 
 got_cpu_context: