Skip to contentSkip to conversation

perf: xgene: Add CPU hotplug support

PATCH Superseded Hoan Tran 3 participants 4 messages Nov 7, 2018 – Nov 21, 2018

Subsystems (3)
lore
Share & tools
lore

Hoan Tran

author
#0 lore raw

PATCH v3 1/1 perf: xgene: Add CPU hotplug support

From: Hoan Tran <[email protected]>

This patch adds CPU hotplug support where the PMU migrates the context to another online CPU when its CPU is offline.

It fixes the below issue where the user does offline the CPU which is assigned to this PMU.

Assuming, CPU0 is assigned for this PMU. When the user does offline CPU0

	[root@(none) ~]# echo 0 > /sys/devices/system/cpu/cpu0/online

This PMU does not work anymore and shows the below error.
[root@(none) ~]# perf stat -a -e l3c0/cycle-count/,l3c0/write/ sleep 1
Error:
The sys_perf_event_open() syscall returned with 19 (No such device) for event (l3c0/cycle-count/). /bin/dmesg may provide additional information.
No CONFIG_PERF_EVENTS=y kernel support configured?

With this patch, when CPU0 is offline, PMU migrates to another online CPU and works on that CPU.

---
v3:
* Remove email footer
* Fix the space issue

v2:
* Remove the cpuhp instance when unregistering the PMU

 drivers/perf/xgene_pmu.c   | 80 ++++++++++++++++++++++++++++++++++++++++++----
 include/linux/cpuhotplug.h |  1 +
 2 files changed, 74 insertions(+), 7 deletions(-)
drivers/perf/xgene_pmu.c +73 -7
index 0e31f13..796fcb5 100644
@@ -21,6 +21,7 @@
 
 #include <linux/acpi.h>
 #include <linux/clk.h>
+#include <linux/cpuhotplug.h>
 #include <linux/cpumask.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -130,12 +131,14 @@ struct xgene_pmu_ops {
 
 struct xgene_pmu {
 	struct device *dev;
+	struct hlist_node node;
 	int version;
 	void __iomem *pcppmu_csr;
 	u32 mcb_active_mask;
 	u32 mc_active_mask;
 	u32 l3c_active_mask;
 	cpumask_t cpu;
+	int irq;
 	raw_spinlock_t lock;
 	const struct xgene_pmu_ops *ops;
 	struct list_head l3cpmus;
@@ -1806,6 +1809,53 @@ static const struct acpi_device_id xgene_pmu_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, xgene_pmu_acpi_match);
 #endif
 
+static int xgene_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
+{
+	struct xgene_pmu *xgene_pmu = hlist_entry_safe(node, struct xgene_pmu,
+						       node);
+
+	if (cpumask_empty(&xgene_pmu->cpu))
+		cpumask_set_cpu(cpu, &xgene_pmu->cpu);
+
+	/* Overflow interrupt also should use the same CPU */
+	WARN_ON(irq_set_affinity(xgene_pmu->irq, &xgene_pmu->cpu));
+
+	return 0;
+}
+
+static int xgene_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
+{
+	struct xgene_pmu *xgene_pmu = hlist_entry_safe(node, struct xgene_pmu,
+						       node);
+	struct xgene_pmu_dev_ctx *ctx;
+	unsigned int target;
+
+	if (!cpumask_test_and_clear_cpu(cpu, &xgene_pmu->cpu))
+		return 0;
+	target = cpumask_any_but(cpu_online_mask, cpu);
+	if (target >= nr_cpu_ids)
+		return 0;
+
+	list_for_each_entry(ctx, &xgene_pmu->mcpmus, next) {
+		perf_pmu_migrate_context(&ctx->pmu_dev->pmu, cpu, target);
+	}
+	list_for_each_entry(ctx, &xgene_pmu->mcbpmus, next) {
+		perf_pmu_migrate_context(&ctx->pmu_dev->pmu, cpu, target);
+	}
+	list_for_each_entry(ctx, &xgene_pmu->l3cpmus, next) {
+		perf_pmu_migrate_context(&ctx->pmu_dev->pmu, cpu, target);
+	}
+	list_for_each_entry(ctx, &xgene_pmu->iobpmus, next) {
+		perf_pmu_migrate_context(&ctx->pmu_dev->pmu, cpu, target);
+	}
+
+	cpumask_set_cpu(target, &xgene_pmu->cpu);
+	/* Overflow interrupt also should use the same CPU */
+	WARN_ON(irq_set_affinity(xgene_pmu->irq, &xgene_pmu->cpu));
+
+	return 0;
+}
+
 static int xgene_pmu_probe(struct platform_device *pdev)
 {
 	const struct xgene_pmu_data *dev_data;
@@ -1815,6 +1865,14 @@ static int xgene_pmu_probe(struct platform_device *pdev)
 	int irq, rc;
 	int version;
 
+	/* Install a hook to update the reader CPU in case it goes offline */
+	rc = cpuhp_setup_state_multi(CPUHP_AP_PERF_XGENE_ONLINE,
+				      "CPUHP_AP_PERF_XGENE_ONLINE",
+				      xgene_pmu_online_cpu,
+				      xgene_pmu_offline_cpu);
+	if (rc)
+		return rc;
+
 	xgene_pmu = devm_kzalloc(&pdev->dev, sizeof(*xgene_pmu), GFP_KERNEL);
 	if (!xgene_pmu)
 		return -ENOMEM;
@@ -1865,6 +1923,7 @@ static int xgene_pmu_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "No IRQ resource\n");
 		return -EINVAL;
 	}
+
 	rc = devm_request_irq(&pdev->dev, irq, xgene_pmu_isr,
 				IRQF_NOBALANCING | IRQF_NO_THREAD,
 				dev_name(&pdev->dev), xgene_pmu);
@@ -1873,6 +1932,8 @@ static int xgene_pmu_probe(struct platform_device *pdev)
 		return rc;
 	}
 
+	xgene_pmu->irq = irq;
+
 	raw_spin_lock_init(&xgene_pmu->lock);
 
 	/* Check for active MCBs and MCUs */
@@ -1883,13 +1944,11 @@ static int xgene_pmu_probe(struct platform_device *pdev)
 		xgene_pmu->mc_active_mask = 0x1;
 	}
 
-	/* Pick one core to use for cpumask attributes */
-	cpumask_set_cpu(smp_processor_id(), &xgene_pmu->cpu);
-
-	/* Make sure that the overflow interrupt is handled by this CPU */
-	rc = irq_set_affinity(irq, &xgene_pmu->cpu);
+	/* Add this instance to the list used by the hotplug callback */
+	rc = cpuhp_state_add_instance(CPUHP_AP_PERF_XGENE_ONLINE,
+				      &xgene_pmu->node);
 	if (rc) {
-		dev_err(&pdev->dev, "Failed to set interrupt affinity!\n");
+		dev_err(&pdev->dev, "Error %d registering hotplug", rc);
 		return rc;
 	}
 
@@ -1897,13 +1956,18 @@ static int xgene_pmu_probe(struct platform_device *pdev)
 	rc = xgene_pmu_probe_pmu_dev(xgene_pmu, pdev);
 	if (rc) {
 		dev_err(&pdev->dev, "No PMU perf devices found!\n");
-		return rc;
+		goto out_unregister;
 	}
 
 	/* Enable interrupt */
 	xgene_pmu->ops->unmask_int(xgene_pmu);
 
 	return 0;
+
+out_unregister:
+	cpuhp_state_remove_instance(CPUHP_AP_PERF_XGENE_ONLINE,
+				    &xgene_pmu->node);
+	return rc;
 }
 
 static void
@@ -1924,6 +1988,8 @@ static int xgene_pmu_remove(struct platform_device *pdev)
 	xgene_pmu_dev_cleanup(xgene_pmu, &xgene_pmu->iobpmus);
 	xgene_pmu_dev_cleanup(xgene_pmu, &xgene_pmu->mcbpmus);
 	xgene_pmu_dev_cleanup(xgene_pmu, &xgene_pmu->mcpmus);
+	cpuhp_state_remove_instance(CPUHP_AP_PERF_XGENE_ONLINE,
+				    &xgene_pmu->node);
 
 	return 0;
 }
include/linux/cpuhotplug.h +1 -0
index 8796ba3..afefca8a 100644
@@ -164,6 +164,7 @@ enum cpuhp_state {
 	CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE,
 	CPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE,
 	CPUHP_AP_PERF_POWERPC_THREAD_IMC_ONLINE,
+	CPUHP_AP_PERF_XGENE_ONLINE,
 	CPUHP_AP_WORKQUEUE_ONLINE,
 	CPUHP_AP_RCUTREE_ONLINE,
 	CPUHP_AP_ONLINE_DYN,
Signature · 1 line
2.7.4
maintainer
#1 lore raw

PATCH v3 1/1 perf: xgene: Add CPU hotplug support

Hi Hoan,

Quoted 20 lines · Hoan Tran

From: Hoan Tran <[email protected]>

This patch adds CPU hotplug support where the PMU migrates the context to another online CPU when its CPU is offline.

It fixes the below issue where the user does offline the CPU which is assigned to this PMU.

Assuming, CPU0 is assigned for this PMU. When the user does offline CPU0

	[root@(none) ~]# echo 0 > /sys/devices/system/cpu/cpu0/online

This PMU does not work anymore and shows the below error.
[root@(none) ~]# perf stat -a -e l3c0/cycle-count/,l3c0/write/ sleep 1
Error:
The sys_perf_event_open() syscall returned with 19 (No such device) for event (l3c0/cycle-count/). /bin/dmesg may provide additional information.
No CONFIG_PERF_EVENTS=y kernel support configured?

With this patch, when CPU0 is offline, PMU migrates to another online CPU and works on that CPU.

Quoted 8 lines

---
v3:
* Remove email footer
* Fix the space issue

v2:
* Remove the cpuhp instance when unregistering the PMU

Aside from one minor fixup below, this looks good to me, and with that applied:

Will, are you happy to apply that fixup when picking the patch?

[...]

include/linux/cpuhotplug.h enum cpuhp_state { · line 167

Quoted 9 lines
include/linux/cpuhotplug.h +1 -0
index 8796ba3..afefca8a 100644
@@ -164,6 +164,7 @@ enum cpuhp_state {
 	CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE,
 	CPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE,
 	CPUHP_AP_PERF_POWERPC_THREAD_IMC_ONLINE,
+	CPUHP_AP_PERF_XGENE_ONLINE,

All the other ARM vendors have named their callbacks with a prefix:

	CPUHP_AP_PERF_ARM_*

... e.g.

CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE,
CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,

... for consistency I'd prefer if we could rename this state to:

CPUHP_AP_PERF_ARM_XGENE_ONLINE,

... or:

CPUHP_AP_PERF_ARM_APM_XGENE_ONLINE,

... and place it adjacent to those other entries, fixing up the uses as appropriate.

Thanks,
Mark.

#2 lore raw

PATCH v3 1/1 perf: xgene: Add CPU hotplug support

Quoted 30 lines · Mark Rutland
Quoted 20 lines · Hoan Tran

From: Hoan Tran <[email protected]>

This patch adds CPU hotplug support where the PMU migrates the context to another online CPU when its CPU is offline.

It fixes the below issue where the user does offline the CPU which is assigned to this PMU.

Assuming, CPU0 is assigned for this PMU. When the user does offline CPU0

	[root@(none) ~]# echo 0 > /sys/devices/system/cpu/cpu0/online

This PMU does not work anymore and shows the below error.
[root@(none) ~]# perf stat -a -e l3c0/cycle-count/,l3c0/write/ sleep 1
Error:
The sys_perf_event_open() syscall returned with 19 (No such device) for event (l3c0/cycle-count/). /bin/dmesg may provide additional information.
No CONFIG_PERF_EVENTS=y kernel support configured?

With this patch, when CPU0 is offline, PMU migrates to another online CPU and works on that CPU.

Quoted 8 lines

---
v3:
* Remove email footer
* Fix the space issue

v2:
* Remove the cpuhp instance when unregistering the PMU

Quoted 6 lines

Aside from one minor fixup below, this looks good to me, and with that applied:

Will, are you happy to apply that fixup when picking the patch?

Thanks, Mark. I'll queue this up and fix the naming of the enum entry.

Will

author
#3 lore raw

PATCH v3 1/1 perf: xgene: Add CPU hotplug support

Thanks, Mark and Will !

Regards

Hoan

Quoted 39 lines · Will Deacon
Quoted 27 lines · Mark Rutland
Quoted 26 lines · Hoan Tran

From: Hoan Tran <[email protected]>

This patch adds CPU hotplug support where the PMU migrates the context to another online CPU when its CPU is offline.

It fixes the below issue where the user does offline the CPU which is assigned to this PMU.

Assuming, CPU0 is assigned for this PMU. When the user does offline CPU0

	[root@(none) ~]# echo 0 > /sys/devices/system/cpu/cpu0/online

This PMU does not work anymore and shows the below error.
[root@(none) ~]# perf stat -a -e l3c0/cycle-count/,l3c0/write/ sleep 1
Error:
The sys_perf_event_open() syscall returned with 19 (No such device) for event (l3c0/cycle-count/). /bin/dmesg may provide additional information.
No CONFIG_PERF_EVENTS=y kernel support configured?

With this patch, when CPU0 is offline, PMU migrates to another online CPU and works on that CPU.

---
v3:
* Remove email footer
* Fix the space issue

Quoted 8 lines
Quoted 2 lines

v2:
* Remove the cpuhp instance when unregistering the PMU

Aside from one minor fixup below, this looks good to me, and with that applied:

Will, are you happy to apply that fixup when picking the patch?

Thanks, Mark. I'll queue this up and fix the naming of the enum entry.

Will