diff mbox series

[2/8] drivers/perf: hisi: Improve the detection of associated CPUs

Message ID 20241018095745.57057-3-yangyicong@huawei.com (mailing list archive)
State New
Headers show
Series Refactor the common parts to the HiSilicon Uncore PMU core and cleanups | expand

Commit Message

Yicong Yang Oct. 18, 2024, 9:57 a.m. UTC
From: Yicong Yang <yangyicong@hisilicon.com>

Currently we detect the associated CPUs in the cpuhp online callback.
If the CPU's sccl_id or the ccl_id matches the PMU's, they're
associated. There's an exception that some PMUs locate on the SICL
and will match no CPUs. The events of these PMUs can be opened on
any online CPUs. To handle this we just check whether the PMU's
sccl_id is -1, if so we know it locates on SICL and make any CPU
associated to it.

This can be tweaked so in this patch just do the below changes:
- If the PMU doesn't match any CPU then associated it to online CPUs
- Choose the target CPU according to the NUMA affinity for opening
  events

The function is implemented by hisi_pmu_init_associated_cpus() and
invoked in hisi_pmu_init().

Also we maintained the associated_cpus with all the online CPUs. This
is redundant since we'll always schedule the events on the online CPUs.
Get rid of this and make associated_cpus contain offline CPUs as well.

Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
---
 drivers/perf/hisilicon/hisi_uncore_pmu.c | 56 +++++++++++++++++++-----
 drivers/perf/hisilicon/hisi_uncore_pmu.h |  5 +++
 2 files changed, 49 insertions(+), 12 deletions(-)
diff mbox series

Patch

diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c
index 416f72a813fc..5b9373d25f9d 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.c
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c
@@ -399,6 +399,27 @@  void hisi_uncore_pmu_disable(struct pmu *pmu)
 }
 EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_disable, HISI_PMU);
 
+static void hisi_pmu_init_associated_cpus(struct hisi_pmu *hisi_pmu)
+{
+	/*
+	 * If the associated_cpus has already been initialized, for example
+	 * determined by comparing the sccl_id and ccl_id with the CPU's
+	 * mpidr_el1, then do nothing here. Otherwise the PMU has no affinity
+	 * and could be opened on any online CPU.
+	 */
+	if (!cpumask_empty(&hisi_pmu->associated_cpus))
+		return;
+
+	cpumask_copy(&hisi_pmu->associated_cpus, cpu_online_mask);
+	hisi_pmu->dummy_associated_cpus = true;
+
+	/*
+	 * Otherwise the associated CPUs haven't been online yet. Pick a
+	 * nearest CPU according to the PMU's numa node instead.
+	 */
+	hisi_pmu->on_cpu = cpumask_local_spread(0, dev_to_node(hisi_pmu->dev));
+	WARN_ON(irq_set_affinity(hisi_pmu->irq, cpumask_of(hisi_pmu->on_cpu)));
+}
 
 /*
  * The Super CPU Cluster (SCCL) and CPU Cluster (CCL) IDs can be
@@ -446,10 +467,6 @@  static bool hisi_pmu_cpu_is_associated_pmu(struct hisi_pmu *hisi_pmu)
 {
 	int sccl_id, ccl_id;
 
-	/* If SCCL_ID is -1, the PMU is in a SICL and has no CPU affinity */
-	if (hisi_pmu->sccl_id == -1)
-		return true;
-
 	if (hisi_pmu->ccl_id == -1) {
 		/* If CCL_ID is -1, the PMU only shares the same SCCL */
 		hisi_read_sccl_and_ccl_id(&sccl_id, NULL);
@@ -467,13 +484,29 @@  int hisi_uncore_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
 	struct hisi_pmu *hisi_pmu = hlist_entry_safe(node, struct hisi_pmu,
 						     node);
 
-	if (!hisi_pmu_cpu_is_associated_pmu(hisi_pmu))
-		return 0;
+	/*
+	 * If the CPU is not in the associated_cpus, it maybe a new CPU we didn't
+	 * access. Test whether it's associated or not.
+	 */
+	if (!cpumask_test_cpu(cpu, &hisi_pmu->associated_cpus)) {
+		if (!hisi_pmu_cpu_is_associated_pmu(hisi_pmu))
+			return 0;
+
+		/*
+		 * We found an associated CPU so we don't need to use the dummy
+		 * associated CPUs. Update it.
+		 */
+		if (hisi_pmu->dummy_associated_cpus) {
+			cpumask_clear(&hisi_pmu->associated_cpus);
+			hisi_pmu->dummy_associated_cpus = false;
+		}
 
-	cpumask_set_cpu(cpu, &hisi_pmu->associated_cpus);
+		cpumask_set_cpu(cpu, &hisi_pmu->associated_cpus);
+	}
 
-	/* If another CPU is already managing this PMU, simply return. */
-	if (hisi_pmu->on_cpu != -1)
+	/* If another associated CPU is already managing this PMU, simply return. */
+	if (hisi_pmu->on_cpu != -1 &&
+	    cpumask_test_cpu(hisi_pmu->on_cpu, &hisi_pmu->associated_cpus))
 		return 0;
 
 	/* Use this CPU in cpumask for event counting */
@@ -492,9 +525,6 @@  int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
 						     node);
 	unsigned int target;
 
-	if (!cpumask_test_and_clear_cpu(cpu, &hisi_pmu->associated_cpus))
-		return 0;
-
 	/* Nothing to do if this CPU doesn't own the PMU */
 	if (hisi_pmu->on_cpu != cpu)
 		return 0;
@@ -521,6 +551,8 @@  void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module)
 {
 	struct pmu *pmu = &hisi_pmu->pmu;
 
+	hisi_pmu_init_associated_cpus(hisi_pmu);
+
 	pmu->module             = module;
 	pmu->parent             = hisi_pmu->dev;
 	pmu->task_ctx_nr        = perf_invalid_context;
diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h
index 008f18bbef7e..30f824173bcf 100644
--- a/drivers/perf/hisilicon/hisi_uncore_pmu.h
+++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h
@@ -91,6 +91,11 @@  struct hisi_pmu {
 	struct hisi_pmu_hwevents pmu_events;
 	/* associated_cpus: All CPUs associated with the PMU */
 	cpumask_t associated_cpus;
+	/*
+	 * If the real associated CPUs not onlined by the time initializing,
+	 * we'll initialize with online CPUs and indicate it.
+	 */
+	bool dummy_associated_cpus;
 	/* CPU used for counting */
 	int on_cpu;
 	int irq;