Skip to contentSkip to conversation

Cavium ThunderX uncore PMU support

PATCH Superseded Jan Glauber 4 participants 25 messages Mar 9, 2016 – Sep 16, 2016 1 message not in the archive Arm PMU profiling and debugging

v2 of 10 Superseded Latest is v10 →

lore
Share & tools
lore
#0 lore raw

v2 cover Cavium ThunderX uncore PMU support

This patch series provides access to various counters on the ThunderX SOC.

For details of the uncore implementation see patch #1.

Patches #2-5 add the various ThunderX specific PMUs.

As suggested I've put the files under drivers/perf/uncore. I would prefer this location over drivers/bus because not all of the uncore drivers are bus related.

Changes to v1:
- Added NUMA support
- Fixed CPU hotplug by pmu migration
- Moved files to drivers/perf/uncore
- Removed OCX FRC and LNE drivers, these will fit better into a edac driver
- improved comments abount overflow interrupts
- removed max device limit
- trimmed include files

Feedback welcome!
Jan

-------------------------------------------------

Jan Glauber (5):
arm64/perf: Basic uncore counter support for Cavium ThunderX arm64/perf: Cavium ThunderX L2C TAD uncore support arm64/perf: Cavium ThunderX L2C CBC uncore support arm64/perf: Cavium ThunderX LMC uncore support arm64/perf: Cavium ThunderX OCX TLK uncore support

 drivers/perf/Makefile                       |   1 +
 drivers/perf/uncore/Makefile                |   5 +
 drivers/perf/uncore/uncore_cavium.c         | 314 +++++++++++++++
 drivers/perf/uncore/uncore_cavium.h         |  95 +++++
 drivers/perf/uncore/uncore_cavium_l2c_cbc.c | 237 +++++++++++
 drivers/perf/uncore/uncore_cavium_l2c_tad.c | 600 ++++++++++++++++++++++++++++
 drivers/perf/uncore/uncore_cavium_lmc.c     | 196 +++++++++
 drivers/perf/uncore/uncore_cavium_ocx_tlk.c | 380 ++++++++++++++++++
 8 files changed, 1828 insertions(+)
 create mode 100644 drivers/perf/uncore/Makefile
 create mode 100644 drivers/perf/uncore/uncore_cavium.c
 create mode 100644 drivers/perf/uncore/uncore_cavium.h
 create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_cbc.c
 create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_tad.c
 create mode 100644 drivers/perf/uncore/uncore_cavium_lmc.c
 create mode 100644 drivers/perf/uncore/uncore_cavium_ocx_tlk.c
Signature · 1 line
1.9.1
#1 lore raw

PATCH v2 1/5 arm64/perf: Basic uncore counter support for Cavium ThunderX

Provide "uncore" facilities for different non-CPU performance counter units. Based on Intel/AMD uncore pmu support.

The uncore drivers cover quite different functionality including L2 Cache, memory controllers and interconnects.

The uncore PMUs can be found under /sys/bus/event_source/devices. All counters are exported via sysfs in the corresponding events files under the PMU directory so the perf tool can list the event names.

There are some points that are special in this implementation:

1) The PMU detection relies on PCI device detection. If a matching PCI device is found the PMU is created. The code can deal with multiple units of the same type, e.g. more than one memory controller.
Note: There is also a CPUID check to determine the CPU variant, this is needed to support different hardware versions that use the same PCI IDs.

2) Counters are summarized across different units of the same type on one NUMA node.
For instance L2C TAD 0..7 are presented as a single counter (adding the values from TAD 0 to 7). Although losing the ability to read a single value the merged values are easier to use.

3) NUMA support. The device node id is used to group devices by node so counters on one node can be merged. The NUMA node can be selected via a new sysfs node attribute.
Without NUMA support all devices will be on node 0.

4) All counters are 64 bit wide without overflow interrupts.

---
 drivers/perf/Makefile               |   1 +
 drivers/perf/uncore/Makefile        |   1 +
 drivers/perf/uncore/uncore_cavium.c | 301 ++++++++++++++++++++++++++++++++++++
 drivers/perf/uncore/uncore_cavium.h |  78 ++++++++++
 4 files changed, 381 insertions(+)
 create mode 100644 drivers/perf/uncore/Makefile
 create mode 100644 drivers/perf/uncore/uncore_cavium.c
 create mode 100644 drivers/perf/uncore/uncore_cavium.h
drivers/perf/Makefile +1 -0
index acd2397..61b6084 100644
@@ -1 +1,2 @@
 obj-$(CONFIG_ARM_PMU) += arm_pmu.o
+obj-$(CONFIG_ARCH_THUNDER) += uncore/
drivers/perf/uncore/Makefile new file +1 -0
new file mode 100644
index 0000000..b9c72c2
@@ -0,0 +1 @@
+obj-$(CONFIG_ARCH_THUNDER) += uncore_cavium.o
drivers/perf/uncore/uncore_cavium.c new file +301 -0

301 lines not on this page · raw message

drivers/perf/uncore/uncore_cavium.h new file +78 -0

78 lines not on this page · raw message

Signature · 1 line
1.9.1
#4 lore raw

PATCH v2 2/5 arm64/perf: Cavium ThunderX L2C TAD uncore support

In reply to Jan Glauber

Support counters of the L2 Cache tag and data units.

Also support pass2 added/modified counters by checking MIDR.

---
 drivers/perf/uncore/Makefile                |   3 +-
 drivers/perf/uncore/uncore_cavium.c         |   6 +-
 drivers/perf/uncore/uncore_cavium.h         |   7 +-
 drivers/perf/uncore/uncore_cavium_l2c_tad.c | 600 ++++++++++++++++++++++++++++
 4 files changed, 613 insertions(+), 3 deletions(-)
 create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_tad.c
drivers/perf/uncore/Makefile +2 -1
index b9c72c2..6a16caf 100644
@@ -1 +1,2 @@
-obj-$(CONFIG_ARCH_THUNDER) += uncore_cavium.o
+obj-$(CONFIG_ARCH_THUNDER) += uncore_cavium.o		\
+			      uncore_cavium_l2c_tad.o
drivers/perf/uncore/uncore_cavium.c +5 -1
index 4fd5e45..b92b2ae 100644
@@ -15,7 +15,10 @@ int thunder_uncore_version;
 
 struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event)
 {
-	return NULL;
+	if (event->pmu->type == thunder_l2c_tad_pmu.type)
+		return thunder_uncore_l2c_tad;
+	else
+		return NULL;
 }
 
 void thunder_uncore_read(struct perf_event *event)
@@ -296,6 +299,7 @@ static int __init thunder_uncore_init(void)
 		thunder_uncore_version = 1;
 	pr_info("PMU version: %d\n", thunder_uncore_version);
 
+	thunder_uncore_l2c_tad_setup();
 	return 0;
 }
 late_initcall(thunder_uncore_init);
drivers/perf/uncore/uncore_cavium.h +6 -1
index c799709..7a9c367 100644
@@ -7,7 +7,7 @@
 #define pr_fmt(fmt)     "thunderx_uncore: " fmt
 
 enum uncore_type {
-	NOP_TYPE,
+	L2C_TAD_TYPE,
 };
 
 extern int thunder_uncore_version;
@@ -65,6 +65,9 @@ static inline struct thunder_uncore_node *get_node(u64 config,
 extern struct attribute_group thunder_uncore_attr_group;
 extern struct device_attribute format_attr_node;
 
+extern struct thunder_uncore *thunder_uncore_l2c_tad;
+extern struct pmu thunder_l2c_tad_pmu;
+
 /* Prototypes */
 struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event);
 void thunder_uncore_del(struct perf_event *event, int flags);
@@ -76,3 +79,5 @@ int thunder_uncore_setup(struct thunder_uncore *uncore, int id,
 ssize_t thunder_events_sysfs_show(struct device *dev,
 				  struct device_attribute *attr,
 				  char *page);
+
+int thunder_uncore_l2c_tad_setup(void);
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +600 -0

600 lines not on this page · raw message

Signature · 1 line
1.9.1
#6 lore raw

PATCH v2 3/5 arm64/perf: Cavium ThunderX L2C CBC uncore support

In reply to Jan Glauber

Support counters of the L2 cache crossbar connect.

---
 drivers/perf/uncore/Makefile                |   3 +-
 drivers/perf/uncore/uncore_cavium.c         |   3 +
 drivers/perf/uncore/uncore_cavium.h         |   4 +
 drivers/perf/uncore/uncore_cavium_l2c_cbc.c | 237 ++++++++++++++++++++++++++++
 4 files changed, 246 insertions(+), 1 deletion(-)
 create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_cbc.c
drivers/perf/uncore/Makefile +2 -1
index 6a16caf..d52ecc9 100644
@@ -1,2 +1,3 @@
 obj-$(CONFIG_ARCH_THUNDER) += uncore_cavium.o		\
-			      uncore_cavium_l2c_tad.o
+			      uncore_cavium_l2c_tad.o	\
+			      uncore_cavium_l2c_cbc.o
drivers/perf/uncore/uncore_cavium.c +3 -0
index b92b2ae..a230450 100644
@@ -17,6 +17,8 @@ struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event)
 {
 	if (event->pmu->type == thunder_l2c_tad_pmu.type)
 		return thunder_uncore_l2c_tad;
+	else if (event->pmu->type == thunder_l2c_cbc_pmu.type)
+		return thunder_uncore_l2c_cbc;
 	else
 		return NULL;
 }
@@ -300,6 +302,7 @@ static int __init thunder_uncore_init(void)
 	pr_info("PMU version: %d\n", thunder_uncore_version);
 
 	thunder_uncore_l2c_tad_setup();
+	thunder_uncore_l2c_cbc_setup();
 	return 0;
 }
 late_initcall(thunder_uncore_init);
drivers/perf/uncore/uncore_cavium.h +4 -0
index 7a9c367..94bd02c 100644
@@ -8,6 +8,7 @@
 
 enum uncore_type {
 	L2C_TAD_TYPE,
+	L2C_CBC_TYPE,
 };
 
 extern int thunder_uncore_version;
@@ -66,7 +67,9 @@ extern struct attribute_group thunder_uncore_attr_group;
 extern struct device_attribute format_attr_node;
 
 extern struct thunder_uncore *thunder_uncore_l2c_tad;
+extern struct thunder_uncore *thunder_uncore_l2c_cbc;
 extern struct pmu thunder_l2c_tad_pmu;
+extern struct pmu thunder_l2c_cbc_pmu;
 
 /* Prototypes */
 struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event);
@@ -81,3 +84,4 @@ ssize_t thunder_events_sysfs_show(struct device *dev,
 				  char *page);
 
 int thunder_uncore_l2c_tad_setup(void);
+int thunder_uncore_l2c_cbc_setup(void);
drivers/perf/uncore/uncore_cavium_l2c_cbc.c new file +237 -0

237 lines not on this page · raw message

Signature · 1 line
1.9.1
#8 lore raw

PATCH v2 4/5 arm64/perf: Cavium ThunderX LMC uncore support

In reply to Jan Glauber

Support counters on the DRAM controllers.

Also support pass2 added counters by checking MIDR.

---
 drivers/perf/uncore/Makefile            |   3 +-
 drivers/perf/uncore/uncore_cavium.c     |   3 +
 drivers/perf/uncore/uncore_cavium.h     |   4 +
 drivers/perf/uncore/uncore_cavium_lmc.c | 196 ++++++++++++++++++++++++++++++++
 4 files changed, 205 insertions(+), 1 deletion(-)
 create mode 100644 drivers/perf/uncore/uncore_cavium_lmc.c
drivers/perf/uncore/Makefile +2 -1
index d52ecc9..81479e8 100644
@@ -1,3 +1,4 @@
 obj-$(CONFIG_ARCH_THUNDER) += uncore_cavium.o		\
 			      uncore_cavium_l2c_tad.o	\
-			      uncore_cavium_l2c_cbc.o
+			      uncore_cavium_l2c_cbc.o	\
+			      uncore_cavium_lmc.o
drivers/perf/uncore/uncore_cavium.c +3 -0
index a230450..45c81d0 100644
@@ -19,6 +19,8 @@ struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event)
 		return thunder_uncore_l2c_tad;
 	else if (event->pmu->type == thunder_l2c_cbc_pmu.type)
 		return thunder_uncore_l2c_cbc;
+	else if (event->pmu->type == thunder_lmc_pmu.type)
+		return thunder_uncore_lmc;
 	else
 		return NULL;
 }
@@ -303,6 +305,7 @@ static int __init thunder_uncore_init(void)
 
 	thunder_uncore_l2c_tad_setup();
 	thunder_uncore_l2c_cbc_setup();
+	thunder_uncore_lmc_setup();
 	return 0;
 }
 late_initcall(thunder_uncore_init);
drivers/perf/uncore/uncore_cavium.h +4 -0
index 94bd02c..f14f6be 100644
@@ -9,6 +9,7 @@
 enum uncore_type {
 	L2C_TAD_TYPE,
 	L2C_CBC_TYPE,
+	LMC_TYPE,
 };
 
 extern int thunder_uncore_version;
@@ -68,8 +69,10 @@ extern struct device_attribute format_attr_node;
 
 extern struct thunder_uncore *thunder_uncore_l2c_tad;
 extern struct thunder_uncore *thunder_uncore_l2c_cbc;
+extern struct thunder_uncore *thunder_uncore_lmc;
 extern struct pmu thunder_l2c_tad_pmu;
 extern struct pmu thunder_l2c_cbc_pmu;
+extern struct pmu thunder_lmc_pmu;
 
 /* Prototypes */
 struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event);
@@ -85,3 +88,4 @@ ssize_t thunder_events_sysfs_show(struct device *dev,
 
 int thunder_uncore_l2c_tad_setup(void);
 int thunder_uncore_l2c_cbc_setup(void);
+int thunder_uncore_lmc_setup(void);
drivers/perf/uncore/uncore_cavium_lmc.c new file +196 -0

196 lines not on this page · raw message

Signature · 1 line
1.9.1
#9 lore raw

PATCH v2 5/5 arm64/perf: Cavium ThunderX OCX TLK uncore support

In reply to Jan Glauber

Support for the OCX transmit link counters.

---
 drivers/perf/uncore/Makefile                |   3 +-
 drivers/perf/uncore/uncore_cavium.c         |   3 +
 drivers/perf/uncore/uncore_cavium.h         |   4 +
 drivers/perf/uncore/uncore_cavium_ocx_tlk.c | 380 ++++++++++++++++++++++++++++
 4 files changed, 389 insertions(+), 1 deletion(-)
 create mode 100644 drivers/perf/uncore/uncore_cavium_ocx_tlk.c
drivers/perf/uncore/Makefile +2 -1
index 81479e8..88d1f57 100644
@@ -1,4 +1,5 @@
 obj-$(CONFIG_ARCH_THUNDER) += uncore_cavium.o		\
 			      uncore_cavium_l2c_tad.o	\
 			      uncore_cavium_l2c_cbc.o	\
-			      uncore_cavium_lmc.o
+			      uncore_cavium_lmc.o	\
+			      uncore_cavium_ocx_tlk.o
drivers/perf/uncore/uncore_cavium.c +3 -0
index 45c81d0..e210457 100644
@@ -21,6 +21,8 @@ struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event)
 		return thunder_uncore_l2c_cbc;
 	else if (event->pmu->type == thunder_lmc_pmu.type)
 		return thunder_uncore_lmc;
+	else if (event->pmu->type == thunder_ocx_tlk_pmu.type)
+		return thunder_uncore_ocx_tlk;
 	else
 		return NULL;
 }
@@ -306,6 +308,7 @@ static int __init thunder_uncore_init(void)
 	thunder_uncore_l2c_tad_setup();
 	thunder_uncore_l2c_cbc_setup();
 	thunder_uncore_lmc_setup();
+	thunder_uncore_ocx_tlk_setup();
 	return 0;
 }
 late_initcall(thunder_uncore_init);
drivers/perf/uncore/uncore_cavium.h +4 -0
index f14f6be..78e95c7 100644
@@ -10,6 +10,7 @@ enum uncore_type {
 	L2C_TAD_TYPE,
 	L2C_CBC_TYPE,
 	LMC_TYPE,
+	OCX_TLK_TYPE,
 };
 
 extern int thunder_uncore_version;
@@ -70,9 +71,11 @@ extern struct device_attribute format_attr_node;
 extern struct thunder_uncore *thunder_uncore_l2c_tad;
 extern struct thunder_uncore *thunder_uncore_l2c_cbc;
 extern struct thunder_uncore *thunder_uncore_lmc;
+extern struct thunder_uncore *thunder_uncore_ocx_tlk;
 extern struct pmu thunder_l2c_tad_pmu;
 extern struct pmu thunder_l2c_cbc_pmu;
 extern struct pmu thunder_lmc_pmu;
+extern struct pmu thunder_ocx_tlk_pmu;
 
 /* Prototypes */
 struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event);
@@ -89,3 +92,4 @@ ssize_t thunder_events_sysfs_show(struct device *dev,
 int thunder_uncore_l2c_tad_setup(void);
 int thunder_uncore_l2c_cbc_setup(void);
 int thunder_uncore_lmc_setup(void);
+int thunder_uncore_ocx_tlk_setup(void);
drivers/perf/uncore/uncore_cavium_ocx_tlk.c new file +380 -0

380 lines not on this page · raw message

Signature · 1 line
1.9.1
#10 lore raw
In reply to Jan Glauber

Hi Mark,

can you have a look at these patches?

Thanks,
Jan

Quoted 50 lines · Jan Glauber

This patch series provides access to various counters on the ThunderX SOC.

For details of the uncore implementation see patch #1.

Patches #2-5 add the various ThunderX specific PMUs.

As suggested I've put the files under drivers/perf/uncore. I would prefer this location over drivers/bus because not all of the uncore drivers are bus related.

Changes to v1:
- Added NUMA support
- Fixed CPU hotplug by pmu migration
- Moved files to drivers/perf/uncore
- Removed OCX FRC and LNE drivers, these will fit better into a edac driver
- improved comments abount overflow interrupts
- removed max device limit
- trimmed include files

Feedback welcome!
Jan

-------------------------------------------------

Jan Glauber (5):
arm64/perf: Basic uncore counter support for Cavium ThunderX arm64/perf: Cavium ThunderX L2C TAD uncore support arm64/perf: Cavium ThunderX L2C CBC uncore support arm64/perf: Cavium ThunderX LMC uncore support arm64/perf: Cavium ThunderX OCX TLK uncore support

 drivers/perf/Makefile                       |   1 +
 drivers/perf/uncore/Makefile                |   5 +
 drivers/perf/uncore/uncore_cavium.c         | 314 +++++++++++++++
 drivers/perf/uncore/uncore_cavium.h         |  95 +++++
 drivers/perf/uncore/uncore_cavium_l2c_cbc.c | 237 +++++++++++
 drivers/perf/uncore/uncore_cavium_l2c_tad.c | 600 ++++++++++++++++++++++++++++
 drivers/perf/uncore/uncore_cavium_lmc.c     | 196 +++++++++
 drivers/perf/uncore/uncore_cavium_ocx_tlk.c | 380 ++++++++++++++++++
 8 files changed, 1828 insertions(+)
 create mode 100644 drivers/perf/uncore/Makefile
 create mode 100644 drivers/perf/uncore/uncore_cavium.c
 create mode 100644 drivers/perf/uncore/uncore_cavium.h
 create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_cbc.c
 create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_tad.c
 create mode 100644 drivers/perf/uncore/uncore_cavium_lmc.c
 create mode 100644 drivers/perf/uncore/uncore_cavium_ocx_tlk.c
Signature · 1 line
1.9.1
#19 lore raw
In reply to a message not in the archive

Mark,

are these patches still queued or should I repost them?

--Jan

Quoted 63 lines · Jan Glauber

Hi Mark,

can you have a look at these patches?

Thanks,
Jan

2016-03-09 17:21 GMT+01:00 Jan Glauber <[email protected]>:

This patch series provides access to various counters on the ThunderX SOC.

For details of the uncore implementation see patch #1.

Patches #2-5 add the various ThunderX specific PMUs.

As suggested I've put the files under drivers/perf/uncore. I would prefer this location over drivers/bus because not all of the uncore drivers are bus related.

Changes to v1:
- Added NUMA support
- Fixed CPU hotplug by pmu migration
- Moved files to drivers/perf/uncore
- Removed OCX FRC and LNE drivers, these will fit better into a edac driver
- improved comments abount overflow interrupts
- removed max device limit
- trimmed include files

Feedback welcome!
Jan

-------------------------------------------------

Jan Glauber (5):
? arm64/perf: Basic uncore counter support for Cavium ThunderX ? arm64/perf: Cavium ThunderX L2C TAD uncore support ? arm64/perf: Cavium ThunderX L2C CBC uncore support ? arm64/perf: Cavium ThunderX LMC uncore support
? arm64/perf: Cavium ThunderX OCX TLK uncore support

?drivers/perf/Makefile? ? ? ? ? ? ? ? ? ? ? ?|? ?1 + ?drivers/perf/uncore/Makefile? ? ? ? ? ? ? ? |? ?5 + ?drivers/perf/uncore/uncore_cavium.c? ? ? ? ?| 314 +++++++++++++++ ?drivers/perf/uncore/uncore_cavium.h? ? ? ? ?|? 95 +++++ ?drivers/perf/uncore/uncore_cavium_l2c_cbc.c | 237 +++++++++++ ?drivers/perf/uncore/uncore_cavium_l2c_tad.c | 600
++++++++++++++++++++++++++++
?drivers/perf/uncore/uncore_cavium_lmc.c? ? ?| 196 +++++++++ ?drivers/perf/uncore/uncore_cavium_ocx_tlk.c | 380 ++++++++++++++++++ ?8 files changed, 1828 insertions(+)
?create mode 100644 drivers/perf/uncore/Makefile
?create mode 100644 drivers/perf/uncore/uncore_cavium.c ?create mode 100644 drivers/perf/uncore/uncore_cavium.h ?create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_cbc.c ?create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_tad.c ?create mode 100644 drivers/perf/uncore/uncore_cavium_lmc.c ?create mode 100644 drivers/perf/uncore/uncore_cavium_ocx_tlk.c

--
1.9.1

maintainer
#2 lore raw

Re: [PATCH v2 1/5] arm64/perf: Basic uncore counter support for Cavium ThunderX

In reply to Jan Glauber
Quoted 20 lines · Jan Glauber

Provide "uncore" facilities for different non-CPU performance counter units. Based on Intel/AMD uncore pmu support.

The uncore drivers cover quite different functionality including L2 Cache, memory controllers and interconnects.

The uncore PMUs can be found under /sys/bus/event_source/devices. All counters are exported via sysfs in the corresponding events files under the PMU directory so the perf tool can list the event names.

There are some points that are special in this implementation:

1) The PMU detection relies on PCI device detection. If a matching PCI device is found the PMU is created. The code can deal with multiple units of the same type, e.g. more than one memory controller.
Note: There is also a CPUID check to determine the CPU variant, this is needed to support different hardware versions that use the same PCI IDs.

Quoted 5 lines

2) Counters are summarized across different units of the same type on one NUMA node.
For instance L2C TAD 0..7 are presented as a single counter (adding the values from TAD 0 to 7). Although losing the ability to read a single value the merged values are easier to use.

Merging within a NUMA node, but no further seems a little arbitrary.

Quoted 4 lines

3) NUMA support. The device node id is used to group devices by node so counters on one node can be merged. The NUMA node can be selected via a new sysfs node attribute.
Without NUMA support all devices will be on node 0.

It doesn't seem great that this depends on kernel configuration (which is independent of HW configuration). It seems confusing for the user, and fragile.

Do we not have access to another way of grouping cores (e.g. a socket ID), that's independent of kernel configuration? That seems to be how the x86 uncore PMUs are handled.

If we don't have that information, it really feels like we need additional info from FW (which would also solve the CPUID issue with point 1), or this is likely to be very fragile.

Quoted 37 lines
drivers/perf/uncore/uncore_cavium.c new file +37 -0
+void thunder_uncore_read(struct perf_event *event)
+{
+	struct thunder_uncore *uncore = event_to_thunder_uncore(event);
+	struct hw_perf_event *hwc = &event->hw;
+	struct thunder_uncore_node *node;
+	struct thunder_uncore_unit *unit;
+	u64 prev, new = 0;
+	s64 delta;
+
+	node = get_node(hwc->config, uncore);
+
+	/*
+	 * No counter overflow interrupts so we do not
+	 * have to worry about prev_count changing on us.
+	 */
+	prev = local64_read(&hwc->prev_count);
+
+	/* read counter values from all units on the node */
+	list_for_each_entry(unit, &node->unit_list, entry)
+		new += readq(hwc->event_base + unit->map);
+
+	local64_set(&hwc->prev_count, new);
+	delta = new - prev;
+	local64_add(delta, &event->count);
+}
+
+void thunder_uncore_del(struct perf_event *event, int flags)
+{
+	struct thunder_uncore *uncore = event_to_thunder_uncore(event);
+	struct hw_perf_event *hwc = &event->hw;
+	struct thunder_uncore_node *node;
+	int i;
+
+	event->pmu->stop(event, PERF_EF_UPDATE);
+
+	/*
+	 * For programmable counters we need to check where we installed it.

drivers/perf/uncore/uncore_cavium.c line 67

Quoted 10 lines
drivers/perf/uncore/uncore_cavium.c new file +10 -0
+	 * To keep this function generic always test the more complicated
+	 * case (free running counters won't need the loop).
+	 */
+	node = get_node(hwc->config, uncore);
+	for (i = 0; i < node->num_counters; i++) {
+		if (cmpxchg(&node->events[i], event, NULL) == event)
+			break;
+	}
+	hwc->idx = -1;
+}

It's very difficult to know what's going on here with the lack of a corresponding *_add function. Is there any reason there is not a common implementation, at least for the shared logic?

Similarly, it's difficult to know what state the read function is expecting (e.g. are counters always initialised to 0 to start with)?

Quoted 14 lines
drivers/perf/uncore/uncore_cavium.c new file +14 -0
+int thunder_uncore_event_init(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct thunder_uncore_node *node;
+	struct thunder_uncore *uncore;
+
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	/* we do not support sampling */
+	if (is_sampling_event(event))
+		return -EINVAL;
+
+	/* counters do not have these bits */

drivers/perf/uncore/uncore_cavium.c line 92

Quoted 10 lines
drivers/perf/uncore/uncore_cavium.c new file +10 -0
+	if (event->attr.exclude_user	||
+	    event->attr.exclude_kernel	||
+	    event->attr.exclude_host	||
+	    event->attr.exclude_guest	||
+	    event->attr.exclude_hv	||
+	    event->attr.exclude_idle)
+		return -EINVAL;
+
+	/* counters are 64 bit wide and without overflow interrupts */
+

It would be good to describe the implications of this; otherwise it seems like a floating comment.

drivers/perf/uncore/uncore_cavium.c line 100

Quoted 8 lines
drivers/perf/uncore/uncore_cavium.c new file +8 -0
+	uncore = event_to_thunder_uncore(event);
+	if (!uncore)
+		return -ENODEV;
+	if (!uncore->event_valid(event->attr.config & UNCORE_EVENT_ID_MASK))
+		return -EINVAL;
+
+	/* check NUMA node */
+	node = get_node(event->attr.config, uncore);

As above, I don't think using Linux NUMA node IDs is a good idea, especially for a user-facing ABI.

drivers/perf/uncore/uncore_cavium.c line 109

Quoted 9 lines
drivers/perf/uncore/uncore_cavium.c new file +9 -0
+	if (!node) {
+		pr_debug("Invalid numa node selected\n");
+		return -EINVAL;
+	}
+
+	hwc->config = event->attr.config;
+	hwc->idx = -1;
+	return 0;
+}

What about the CPU handling?

Where do you verify that cpu != -1, and assign the event to a particular CPU prior to the pmu::add callback? That should be common to all of your uncore PMUs, and should live here.

drivers/perf/uncore/uncore_cavium.c line 156

Quoted 7 lines
drivers/perf/uncore/uncore_cavium.c new file +7 -0
+static ssize_t node_show(struct device *dev, struct device_attribute *attr, char *page)
+{
+	if (NODES_SHIFT)
+		return sprintf(page, "config:16-%d\n", 16 + NODES_SHIFT - 1);
+	else
+		return sprintf(page, "config:16\n");
+}

I'm not keen on this depending on the kernel configuration.

drivers/perf/uncore/uncore_cavium.c line 170

Quoted 11 lines
drivers/perf/uncore/uncore_cavium.c new file +11 -0
+static int thunder_uncore_pmu_cpu_notifier(struct notifier_block *nb,
+					   unsigned long action, void *data)
+{
+	struct thunder_uncore *uncore = container_of(nb, struct thunder_uncore, cpu_nb);
+	int new_cpu, old_cpu = (long) data;
+
+	switch (action & ~CPU_TASKS_FROZEN) {
+	case CPU_DOWN_PREPARE:
+		if (!cpumask_test_and_clear_cpu(old_cpu, &thunder_active_mask))
+			break;
+		new_cpu = cpumask_any_but(cpu_online_mask, old_cpu);

Above it was mentioned that events are groups per node/socket. So surely it doesn't make sens to migrate this to any arbitrary CPU, but only CPUs in the same node?

If I have active events for node 0, what happens when I hotplug out the last CPU for that node (but have CPUs online in node 1)?

Is it guaranteed that power is retained for the device?

Quoted 6 lines
drivers/perf/uncore/uncore_cavium.c new file +6 -0
+		if (new_cpu >= nr_cpu_ids)
+			break;
+		perf_pmu_migrate_context(uncore->pmu, old_cpu, new_cpu);
+		cpumask_set_cpu(new_cpu, &thunder_active_mask);
+		break;
+	default:

drivers/perf/uncore/uncore_cavium.c line 186

Quoted 10 lines
drivers/perf/uncore/uncore_cavium.c new file +10 -0
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct thunder_uncore_node *alloc_node(struct thunder_uncore *uncore, int node_id, int counters)
+{
+	struct thunder_uncore_node *node;
+
+	node = kzalloc(sizeof(struct thunder_uncore_node), GFP_KERNEL);

Use:

	node = kzalloc(sizeof(*node), GFP_KERNEL);
Quoted 4 lines
drivers/perf/uncore/uncore_cavium.c new file +4 -0
+int __init thunder_uncore_setup(struct thunder_uncore *uncore, int device_id,
+			 unsigned long offset, unsigned long size,
+			 struct pmu *pmu, int counters)
+{

drivers/perf/uncore/uncore_cavium.c line 207

Quoted 10 lines
drivers/perf/uncore/uncore_cavium.c new file +10 -0
+	struct thunder_uncore_unit  *unit, *tmp;
+	struct thunder_uncore_node *node;
+	struct pci_dev *pdev = NULL;
+	int ret, node_id, found = 0;
+
+	/* detect PCI devices */
+	do {
+		pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, device_id, pdev);
+		if (!pdev)
+			break;

the loop would look cleaner like:

	unsigned int vendor_id = PCI_VENDOR_ID_CAVIUM;

	while ((pdev = pci_get_device(vendor_id, device_id, pdev))) {

		...

	}

drivers/perf/uncore/uncore_cavium.c line 215

Quoted 8 lines
drivers/perf/uncore/uncore_cavium.c new file +8 -0
+
+		node_id = dev_to_node(&pdev->dev);
+		/*
+		 * -1 without NUMA, set to 0 because we always have at
+		 *  least node 0.
+		 */
+		if (node_id < 0)
+			node_id = 0;

Again, this seems fragile to me. I am very much not keen on this behaviour varying based on a logically unrelated kernel configuration option.

drivers/perf/uncore/uncore_cavium.c line 227

Quoted 12 lines
drivers/perf/uncore/uncore_cavium.c new file +12 -0
+
+		/* allocate node if necessary */
+		if (!uncore->nodes[node_id])
+			uncore->nodes[node_id] = alloc_node(uncore, node_id, counters);
+
+		node = uncore->nodes[node_id];
+		if (!node) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		unit = kzalloc(sizeof(struct thunder_uncore_unit), GFP_KERNEL);

Use:
unit = kzalloc(sizeof(*unit), GFP_KERNEL)

drivers/perf/uncore/uncore_cavium.c line 247

Quoted 5 lines
drivers/perf/uncore/uncore_cavium.c new file +5 -0
+	/*
+	 * perf PMU is CPU dependent in difference to our uncore devices.
+	 * Just pick a CPU and migrate away if it goes offline.
+	 */
+	cpumask_set_cpu(smp_processor_id(), &thunder_active_mask);

The current CPU is not guaranteed to be in the same node, no?

My comments earlier w.r.t. migration apply here too.

drivers/perf/uncore/uncore_cavium.c line 259

Quoted 12 lines
drivers/perf/uncore/uncore_cavium.c new file +12 -0
+
+	uncore->cpu_nb.notifier_call = thunder_uncore_pmu_cpu_notifier;
+	uncore->cpu_nb.priority = CPU_PRI_PERF + 1;
+	ret = register_cpu_notifier(&uncore->cpu_nb);
+	if (ret)
+		goto fail;
+
+	ret = perf_pmu_register(pmu, pmu->name, -1);
+	if (ret)
+		goto fail_pmu;
+
+	uncore->pmu = pmu;

Typically, the data related to the PMU is put in a struct which wraps the struct pmu. That allows you to map either way using container_of.

Is there a particular reason for thunder_uncore to not contain the struct PMU, rather than a pointer to it?

Thanks,
Mark.

maintainer
#5 lore raw

Re: [PATCH v2 2/5] arm64/perf: Cavium ThunderX L2C TAD uncore support

In reply to Jan Glauber
Quoted 26 lines · Jan Glauber

Support counters of the L2 Cache tag and data units.

Also support pass2 added/modified counters by checking MIDR.

---
 drivers/perf/uncore/Makefile                |   3 +-
 drivers/perf/uncore/uncore_cavium.c         |   6 +-
 drivers/perf/uncore/uncore_cavium.h         |   7 +-
 drivers/perf/uncore/uncore_cavium_l2c_tad.c | 600 ++++++++++++++++++++++++++++
 4 files changed, 613 insertions(+), 3 deletions(-)
 create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_tad.c
drivers/perf/uncore/Makefile +2 -1
index b9c72c2..6a16caf 100644
@@ -1 +1,2 @@
-obj-$(CONFIG_ARCH_THUNDER) += uncore_cavium.o
+obj-$(CONFIG_ARCH_THUNDER) += uncore_cavium.o		\
+			      uncore_cavium_l2c_tad.o
drivers/perf/uncore/uncore_cavium.c +0 -0
index 4fd5e45..b92b2ae 100644

drivers/perf/uncore/uncore_cavium.c int thunder_uncore_version; · line 22

Quoted 9 lines
drivers/perf/uncore/uncore_cavium.c +4 -1
@@ -15,7 +15,10 @@ int thunder_uncore_version;
 
 struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event)
 {
-	return NULL;
+	if (event->pmu->type == thunder_l2c_tad_pmu.type)
+		return thunder_uncore_l2c_tad;
+	else
+		return NULL;
 }

If thunder_uncore contained the relevant struct pmu, you wouldn't need this function.

You could take event->pmu, and use container_of to get the relevant thunder_uncore.

So please do that and get rid of this function.

Quoted 24 lines
drivers/perf/uncore/uncore_cavium.c +1 -0
 void thunder_uncore_read(struct perf_event *event)
@@ -296,6 +299,7 @@ static int __init thunder_uncore_init(void)
 		thunder_uncore_version = 1;
 	pr_info("PMU version: %d\n", thunder_uncore_version);
 
+	thunder_uncore_l2c_tad_setup();
 	return 0;
 }
 late_initcall(thunder_uncore_init);
drivers/perf/uncore/uncore_cavium.h +1 -1
index c799709..7a9c367 100644
@@ -7,7 +7,7 @@
 #define pr_fmt(fmt)     "thunderx_uncore: " fmt
 
 enum uncore_type {
-	NOP_TYPE,
+	L2C_TAD_TYPE,
 };
 
 extern int thunder_uncore_version;

drivers/perf/uncore/uncore_cavium.h static inline struct thunder_uncore_node *get_node(u64 config, · line 69

Quoted 5 lines
drivers/perf/uncore/uncore_cavium.h +2 -0
@@ -65,6 +65,9 @@ static inline struct thunder_uncore_node *get_node(u64 config,
 extern struct attribute_group thunder_uncore_attr_group;
 extern struct device_attribute format_attr_node;
 
+extern struct thunder_uncore *thunder_uncore_l2c_tad;
+extern struct pmu thunder_l2c_tad_pmu;

The above hopefully means you can get rid of these.

Quoted 15 lines
drivers/perf/uncore/uncore_cavium.h +2 -0
 /* Prototypes */
 struct thunder_uncore *event_to_thunder_uncore(struct perf_event *event);
 void thunder_uncore_del(struct perf_event *event, int flags);
@@ -76,3 +79,5 @@ int thunder_uncore_setup(struct thunder_uncore *uncore, int id,
 ssize_t thunder_events_sysfs_show(struct device *dev,
 				  struct device_attribute *attr,
 				  char *page);
+
+int thunder_uncore_l2c_tad_setup(void);
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +0 -0
new file mode 100644
index 0000000..c8dc305

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 2

Quoted 2 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +2 -0
@@ -0,0 +1,600 @@
+/*
+ * Cavium Thunder uncore PMU support, L2C TAD counters.

It would be good to put an explaination of the TAD unit here, even if just expanding that to Tag And Data.

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 9

Quoted 7 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +7 -0
+ *
+ * Copyright 2016 Cavium Inc.
+ * Author: Jan Glauber <[email protected]>
+ */
+
+#include <linux/slab.h>
+#include <linux/perf_event.h>

Minor nit, but as a general note I'd recommend alphabetically sorting your includes now.

That way any subsequent additions/removals are less likely to cause painful conflicts (so long as they retain that order).

Quoted 10 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +10 -0
+static void thunder_uncore_start(struct perf_event *event, int flags)
+{
+	struct thunder_uncore *uncore = event_to_thunder_uncore(event);
+	struct hw_perf_event *hwc = &event->hw;
+	struct thunder_uncore_node *node;
+	struct thunder_uncore_unit *unit;
+	u64 prev;
+	int id;
+
+	node = get_node(hwc->config, uncore);

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 153

Quoted 10 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +10 -0
+	id = get_id(hwc->config);
+
+	/* restore counter value divided by units into all counters */
+	if (flags & PERF_EF_RELOAD) {
+		prev = local64_read(&hwc->prev_count);
+		prev = prev / node->nr_units;
+
+		list_for_each_entry(unit, &node->unit_list, entry)
+			writeq(prev, hwc->event_base + unit->map);
+	}

It would be vastly simpler to always restore zero into all counters, and to update prev_count to account for this.

That will also save you any rounding loss from the division.

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 159

Quoted 6 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +6 -0
+
+	hwc->state = 0;
+
+	/* write byte in control registers for all units on the node */
+	list_for_each_entry(unit, &node->unit_list, entry)
+		writeb(id, hwc->config_base + unit->map);

That comment isn't very helpful. What is the intent and effect of this write?

Quoted 22 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +22 -0
+
+	perf_event_update_userpage(event);
+}
+
+static void thunder_uncore_stop(struct perf_event *event, int flags)
+{
+	struct thunder_uncore *uncore = event_to_thunder_uncore(event);
+	struct hw_perf_event *hwc = &event->hw;
+	struct thunder_uncore_node *node;
+	struct thunder_uncore_unit *unit;
+
+	/* reset selection value for all units on the node */
+	node = get_node(hwc->config, uncore);
+
+	list_for_each_entry(unit, &node->unit_list, entry)
+		writeb(L2C_TAD_EVENTS_DISABLED, hwc->config_base + unit->map);
+	hwc->state |= PERF_HES_STOPPED;
+
+	if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+		thunder_uncore_read(event);
+		hwc->state |= PERF_HES_UPTODATE;
+	}

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 191

Quoted 10 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +10 -0
+}
+
+static int thunder_uncore_add(struct perf_event *event, int flags)
+{
+	struct thunder_uncore *uncore = event_to_thunder_uncore(event);
+	struct hw_perf_event *hwc = &event->hw;
+	struct thunder_uncore_node *node;
+	int i;
+
+	WARN_ON_ONCE(!uncore);

This is trivially never possible if uncore contains the pmu (or we couldn't have initialised the event in the first place).

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 196

Quoted 5 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +5 -0
+	node = get_node(hwc->config, uncore);
+
+	/* are we already assigned? */
+	if (hwc->idx != -1 && node->events[hwc->idx] == event)
+		goto out;

Why would the event already be assigned a particular counter?

Which other piece of code might do that?

As far as I can see, nothing else can.

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 203

Quoted 7 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +7 -0
+
+	for (i = 0; i < node->num_counters; i++) {
+		if (node->events[i] == event) {
+			hwc->idx = i;
+			goto out;
+		}
+	}

This should never happen, in the absence of a programming error. An event should not be added multiple times, and adds and dels should be balanced.

Quoted 6 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +6 -0
+
+	/* if not take the first available counter */
+	hwc->idx = -1;
+	for (i = 0; i < node->num_counters; i++) {
+		if (cmpxchg(&node->events[i], NULL, event) == NULL) {
+			hwc->idx = i;

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 219

Quoted 10 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +10 -0
+			break;
+		}
+	}
+out:
+	if (hwc->idx == -1)
+		return -EBUSY;
+
+	hwc->config_base = hwc->idx;
+	hwc->event_base = L2C_TAD_COUNTER_OFFSET +
+			  hwc->idx * sizeof(unsigned long long);

What's going on here?

I see that we write use hwc->event_base as an offset into registers in the HW, so a sizeof unsigned long long is unusual.

I'm guessing that you're figuring out the address of a 64 bit register. A comment, and sizeof(u64) would be better.

Quoted 18 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +17 -0
+EVENT_ATTR(l2t_hit,	L2C_TAD_EVENT_L2T_HIT);
+EVENT_ATTR(l2t_miss,	L2C_TAD_EVENT_L2T_MISS);
+EVENT_ATTR(l2t_noalloc,	L2C_TAD_EVENT_L2T_NOALLOC);
+EVENT_ATTR(l2_vic,	L2C_TAD_EVENT_L2_VIC);
+EVENT_ATTR(sc_fail,	L2C_TAD_EVENT_SC_FAIL);
+EVENT_ATTR(sc_pass,	L2C_TAD_EVENT_SC_PASS);
+EVENT_ATTR(lfb_occ,	L2C_TAD_EVENT_LFB_OCC);
+EVENT_ATTR(wait_lfb,	L2C_TAD_EVENT_WAIT_LFB);
+EVENT_ATTR(wait_vab,	L2C_TAD_EVENT_WAIT_VAB);
+EVENT_ATTR(rtg_hit,	L2C_TAD_EVENT_RTG_HIT);
+EVENT_ATTR(rtg_miss,	L2C_TAD_EVENT_RTG_MISS);
+EVENT_ATTR(l2_rtg_vic,	L2C_TAD_EVENT_L2_RTG_VIC);
+EVENT_ATTR(l2_open_oci,	L2C_TAD_EVENT_L2_OPEN_OCI);
 
+static struct attribute *thunder_l2c_tad_events_attr[] = {
+	EVENT_PTR(l2t_hit),
+	EVENT_PTR(l2t_miss),
+	EVENT_PTR(l2t_noalloc),

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 307

Quoted 10 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +10 -0
+	EVENT_PTR(l2_vic),
+	EVENT_PTR(sc_fail),
+	EVENT_PTR(sc_pass),
+	EVENT_PTR(lfb_occ),
+	EVENT_PTR(wait_lfb),
+	EVENT_PTR(wait_vab),
+	EVENT_PTR(rtg_hit),
+	EVENT_PTR(rtg_miss),
+	EVENT_PTR(l2_rtg_vic),
+	EVENT_PTR(l2_open_oci),

This duplication is tedious.

Please do something like we did for CCI in commit 5e442eba342e567e ("arm-cci: simplify sysfs attr handling") so you only need to define each attribute once to create it and place it in the relevant attribute pointer list.

Likewise for the other PMUs.

Quoted 14 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +14 -0
+static struct attribute_group thunder_l2c_tad_events_group = {
+	.name = "events",
+	.attrs = NULL,
+};
+
+static const struct attribute_group *thunder_l2c_tad_attr_groups[] = {
+	&thunder_uncore_attr_group,
+	&thunder_l2c_tad_format_group,
+	&thunder_l2c_tad_events_group,
+	NULL,
+};
+
+struct pmu thunder_l2c_tad_pmu = {
+	.attr_groups	= thunder_l2c_tad_attr_groups,

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 544

Quoted 10 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +10 -0
+	.name		= "thunder_l2c_tad",
+	.event_init	= thunder_uncore_event_init,
+	.add		= thunder_uncore_add,
+	.del		= thunder_uncore_del,
+	.start		= thunder_uncore_start,
+	.stop		= thunder_uncore_stop,
+	.read		= thunder_uncore_read,
+};
+
+static int event_valid(u64 config)

A bool would be clearer.

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 551

Quoted 7 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +7 -0
+{
+	if ((config > 0 && config <= L2C_TAD_EVENT_WAIT_VAB) ||
+	    config == L2C_TAD_EVENT_RTG_HIT ||
+	    config == L2C_TAD_EVENT_RTG_MISS ||
+	    config == L2C_TAD_EVENT_L2_RTG_VIC ||
+	    config == L2C_TAD_EVENT_L2_OPEN_OCI ||
+	    ((config & 0x80) && ((config & 0xf) <= 3)))

What are these last cases?

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 562

Quoted 11 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +11 -0
+		return 1;
+
+	if (thunder_uncore_version == 1)
+		if (config == L2C_TAD_EVENT_OPEN_CCPI ||
+		    (config >= L2C_TAD_EVENT_LOOKUP &&
+		     config <= L2C_TAD_EVENT_LOOKUP_ALL) ||
+		    (config >= L2C_TAD_EVENT_TAG_ALC_HIT &&
+		     config <= L2C_TAD_EVENT_OCI_RTG_ALC_VIC &&
+		     config != 0x4d &&
+		     config != 0x66 &&
+		     config != 0x67))

Likewise, what are these last cases?

Why not rule these out explicitly first?

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 573

Quoted 11 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +11 -0
+			return 1;
+
+	return 0;
+}
+
+int __init thunder_uncore_l2c_tad_setup(void)
+{
+	int ret = -ENOMEM;
+
+	thunder_uncore_l2c_tad = kzalloc(sizeof(struct thunder_uncore),
+					 GFP_KERNEL);

As previously, sizeof(*ptr) is preferred to sizeof(type), though it doesn't save you anything here.

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 586

Quoted 13 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +13 -0
+	if (!thunder_uncore_l2c_tad)
+		goto fail_nomem;
+
+	if (thunder_uncore_version == 0)
+		thunder_l2c_tad_events_group.attrs = thunder_l2c_tad_events_attr;
+	else /* default */
+		thunder_l2c_tad_events_group.attrs = thunder_l2c_tad_pass2_events_attr;
+
+	ret = thunder_uncore_setup(thunder_uncore_l2c_tad,
+			   PCI_DEVICE_ID_THUNDER_L2C_TAD,
+			   L2C_TAD_CONTROL_OFFSET,
+			   L2C_TAD_COUNTER_OFFSET + L2C_TAD_NR_COUNTERS
+				* sizeof(unsigned long long),

It would be nicer to calculate the size earlier (with sizeof(u64) as previously mentioned).

drivers/perf/uncore/uncore_cavium_l2c_tad.c line 592

Quoted 6 lines
drivers/perf/uncore/uncore_cavium_l2c_tad.c new file +6 -0
+			   &thunder_l2c_tad_pmu,
+			   L2C_TAD_NR_COUNTERS);
+	if (ret)
+		goto fail;
+
+	thunder_uncore_l2c_tad->type = L2C_TAD_TYPE;

I believe this can go, with thunder_uncore containing a pmu.

Thanks,
Mark.

maintainer
#7 lore raw

Re: [PATCH v2 3/5] arm64/perf: Cavium ThunderX L2C CBC uncore support

In reply to Jan Glauber

drivers/perf/uncore/uncore_cavium.c static int __init thunder_uncore_init(void) · line 308

Quoted 8 lines · Jan Glauber
drivers/perf/uncore/uncore_cavium.c +1 -0
@@ -300,6 +302,7 @@ static int __init thunder_uncore_init(void)
 	pr_info("PMU version: %d\n", thunder_uncore_version);
 
 	thunder_uncore_l2c_tad_setup();
+	thunder_uncore_l2c_cbc_setup();
 	return 0;
 }
 late_initcall(thunder_uncore_init);

Why aren't these just probed independently, as separate PCI devices, rather than using a shared initcall?

You'd have to read the MIDR a few times, but that's a tiny fraction of the rest of the cost of probing, and you can keep the common portion as a stateless library.

drivers/perf/uncore/uncore_cavium_l2c_cbc.c line 45

Quoted 5 lines
drivers/perf/uncore/uncore_cavium_l2c_cbc.c new file +5 -0
+int l2c_cbc_events[L2C_CBC_NR_COUNTERS] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+	0x08, 0x09, 0x0a, 0x0b, 0x0c,
+	0x10, 0x11, 0x12, 0x13
+};

What are these magic numbers?

A comment would be helpful here.

Quoted 13 lines
drivers/perf/uncore/uncore_cavium_l2c_cbc.c new file +13 -0
+
+static void thunder_uncore_start(struct perf_event *event, int flags)
+{
+	struct thunder_uncore *uncore = event_to_thunder_uncore(event);
+	struct hw_perf_event *hwc = &event->hw;
+	struct thunder_uncore_node *node;
+	struct thunder_uncore_unit *unit;
+	u64 prev;
+
+	node = get_node(hwc->config, uncore);
+
+	/* restore counter value divided by units into all counters */
+	if (flags & PERF_EF_RELOAD) {

drivers/perf/uncore/uncore_cavium_l2c_cbc.c line 68

Quoted 10 lines
drivers/perf/uncore/uncore_cavium_l2c_cbc.c new file +10 -0
+		prev = local64_read(&hwc->prev_count);
+		prev = prev / node->nr_units;
+
+		list_for_each_entry(unit, &node->unit_list, entry)
+			writeq(prev, hwc->event_base + unit->map);
+	}
+
+	hwc->state = 0;
+	perf_event_update_userpage(event);
+}

This looks practically identical to the code in patch 2. Please factor the common portion into the library code from patch 1 (zeroing the registers), and share it.

drivers/perf/uncore/uncore_cavium_l2c_cbc.c line 78

Quoted 10 lines
drivers/perf/uncore/uncore_cavium_l2c_cbc.c new file +10 -0
+
+static void thunder_uncore_stop(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+		thunder_uncore_read(event);
+		hwc->state |= PERF_HES_UPTODATE;
+	}
+}

There's no stop control for this PMU?

I was under the impression the core perf code could read the counter while it was stopped, and it would unexpectedly count increasing values.

Does PERF_HES_UPTODATE stop the core from reading the counter, or is it the responsibility of the backend to check that? I see that thunder_uncore_read does not.

Do you need PERF_HES_STOPPED, or does that not matter due to the lack of interrupts?

Quoted 38 lines
drivers/perf/uncore/uncore_cavium_l2c_cbc.c new file +38 -0
+
+static int thunder_uncore_add(struct perf_event *event, int flags)
+{
+	struct thunder_uncore *uncore = event_to_thunder_uncore(event);
+	struct hw_perf_event *hwc = &event->hw;
+	struct thunder_uncore_node *node;
+	int id, i;
+
+	WARN_ON_ONCE(!uncore);
+	node = get_node(hwc->config, uncore);
+	id = get_id(hwc->config);
+
+	/* are we already assigned? */
+	if (hwc->idx != -1 && node->events[hwc->idx] == event)
+		goto out;
+
+	for (i = 0; i < node->num_counters; i++) {
+		if (node->events[i] == event) {
+			hwc->idx = i;
+			goto out;
+		}
+	}
+
+	/* these counters are self-sustained so idx must match the counter! */
+	hwc->idx = -1;
+	for (i = 0; i < node->num_counters; i++) {
+		if (l2c_cbc_events[i] == id) {
+			if (cmpxchg(&node->events[i], NULL, event) == NULL) {
+				hwc->idx = i;
+				break;
+			}
+		}
+	}
+
+out:
+	if (hwc->idx == -1)
+		return -EBUSY;
+

drivers/perf/uncore/uncore_cavium_l2c_cbc.c line 126

Quoted 10 lines
drivers/perf/uncore/uncore_cavium_l2c_cbc.c new file +10 -0
+	hwc->event_base = id * sizeof(unsigned long long);
+
+	/* counter is not stoppable so avoiding PERF_HES_STOPPED */
+	hwc->state = PERF_HES_UPTODATE;
+
+	if (flags & PERF_EF_START)
+		thunder_uncore_start(event, 0);
+
+	return 0;
+}

This looks practically identical to code from path 2, and all my comments there apply.

Please factor this out into the library code in patch 1, taking into account my comments on patch 2.

Likewise, the remainder of the file is mostly a copy+paste of patch 2. All those comments apply equally to this patch.

Thanks,
Mark.

maintainer
#20 lore raw
In reply to Jan Glauber
Quoted 3 lines · Jan Glauber

Mark,

are these patches still queued or should I repost them?

Apologies for the delay. I've just given these a review.

I note an awful lot of duplication over patches 2-5. The pmu::add implementations are practically identical, and I suspect can be shared without much difficulty. Please try to address that unnecessary duplication.

My comments on patches 2 and 3 larely apply to 4 and 5, so I haven't reviewed those individually.

Thanks,
Mark.

Quoted 68 lines

--Jan

Quoted 63 lines · Jan Glauber

Hi Mark,

can you have a look at these patches?

Thanks,
Jan

2016-03-09 17:21 GMT+01:00 Jan Glauber <[email protected]>:

This patch series provides access to various counters on the ThunderX SOC.

For details of the uncore implementation see patch #1.

Patches #2-5 add the various ThunderX specific PMUs.

As suggested I've put the files under drivers/perf/uncore. I would prefer this location over drivers/bus because not all of the uncore drivers are bus related.

Changes to v1:
- Added NUMA support
- Fixed CPU hotplug by pmu migration
- Moved files to drivers/perf/uncore
- Removed OCX FRC and LNE drivers, these will fit better into a edac driver
- improved comments abount overflow interrupts
- removed max device limit
- trimmed include files

Feedback welcome!
Jan

-------------------------------------------------

Jan Glauber (5):
? arm64/perf: Basic uncore counter support for Cavium ThunderX ? arm64/perf: Cavium ThunderX L2C TAD uncore support ? arm64/perf: Cavium ThunderX L2C CBC uncore support ? arm64/perf: Cavium ThunderX LMC uncore support
? arm64/perf: Cavium ThunderX OCX TLK uncore support

?drivers/perf/Makefile? ? ? ? ? ? ? ? ? ? ? ?|? ?1 + ?drivers/perf/uncore/Makefile? ? ? ? ? ? ? ? |? ?5 + ?drivers/perf/uncore/uncore_cavium.c? ? ? ? ?| 314 +++++++++++++++ ?drivers/perf/uncore/uncore_cavium.h? ? ? ? ?|? 95 +++++ ?drivers/perf/uncore/uncore_cavium_l2c_cbc.c | 237 +++++++++++ ?drivers/perf/uncore/uncore_cavium_l2c_tad.c | 600
++++++++++++++++++++++++++++
?drivers/perf/uncore/uncore_cavium_lmc.c? ? ?| 196 +++++++++ ?drivers/perf/uncore/uncore_cavium_ocx_tlk.c | 380 ++++++++++++++++++ ?8 files changed, 1828 insertions(+)
?create mode 100644 drivers/perf/uncore/Makefile
?create mode 100644 drivers/perf/uncore/uncore_cavium.c ?create mode 100644 drivers/perf/uncore/uncore_cavium.h ?create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_cbc.c ?create mode 100644 drivers/perf/uncore/uncore_cavium_l2c_tad.c ?create mode 100644 drivers/perf/uncore/uncore_cavium_lmc.c ?create mode 100644 drivers/perf/uncore/uncore_cavium_ocx_tlk.c

--
1.9.1

#3 lore raw

Re: [PATCH v2 1/5] arm64/perf: Basic uncore counter support for Cavium ThunderX

In reply to Mark Rutland
Quoted 34 lines · Mark Rutland
Quoted 20 lines · Jan Glauber

Provide "uncore" facilities for different non-CPU performance counter units. Based on Intel/AMD uncore pmu support.

The uncore drivers cover quite different functionality including L2 Cache, memory controllers and interconnects.

The uncore PMUs can be found under /sys/bus/event_source/devices. All counters are exported via sysfs in the corresponding events files under the PMU directory so the perf tool can list the event names.

There are some points that are special in this implementation:

1) The PMU detection relies on PCI device detection. If a matching PCI device is found the PMU is created. The code can deal with multiple units of the same type, e.g. more than one memory controller.
Note: There is also a CPUID check to determine the CPU variant, this is needed to support different hardware versions that use the same PCI IDs.

Quoted 5 lines

2) Counters are summarized across different units of the same type on one NUMA node.
For instance L2C TAD 0..7 are presented as a single counter (adding the values from TAD 0 to 7). Although losing the ability to read a single value the merged values are easier to use.

Merging within a NUMA node, but no further seems a little arbitrary.

Quoted 4 lines

3) NUMA support. The device node id is used to group devices by node so counters on one node can be merged. The NUMA node can be selected via a new sysfs node attribute.
Without NUMA support all devices will be on node 0.

Quoted 7 lines

It doesn't seem great that this depends on kernel configuration (which is independent of HW configuration). It seems confusing for the user, and fragile.

Do we not have access to another way of grouping cores (e.g. a socket ID), that's independent of kernel configuration? That seems to be how the x86 uncore PMUs are handled.

I'm not sure how relevant the use case of a multi-node system without CONFIG_NUMA is, but maybe we can get the socket ID from the multiprocessor affinity register (MPIDR_EL1)? The AFF2 part (bits 23:16) should contain the socket number on ThunderX.

Would that be better?

thanks,
Jan

Quoted 3 lines

If we don't have that information, it really feels like we need additional info from FW (which would also solve the CPUID issue with point 1), or this is likely to be very fragile.

#11 lore raw
In reply to Jan Glauber

Hi Jan,

Quoted 3 lines · Jan Glauber

Hi Mark,

can you have a look at these patches?

Looks like Mark reviewed this last week -- are you planning to respin?

Will

#12 lore raw

Hi Will,

Quoted 10 lines · Will Deacon

Hi Jan,

Quoted 3 lines · Jan Glauber

Hi Mark,

can you have a look at these patches?

Looks like Mark reviewed this last week -- are you planning to respin?

Will

Yes, of course. I just had no time yet and I'm a bit lost on how to proceed without using the NUMA node information which Mark did not like to be used.

The only way to know which device is on which node would be to look at the PCI topology (which is also the source of the NUMA node_id). We could do this manually in order to not depend on CONFIG_NUMA, but I would like to know if that is acceptable before respinning the patches.

Thanks!
Jan

#13 lore raw
Quoted 10 lines · Jan Glauber
Quoted 4 lines · Will Deacon
Quoted 1 line · Jan Glauber

can you have a look at these patches?

Looks like Mark reviewed this last week -- are you planning to respin?

Yes, of course. I just had no time yet and I'm a bit lost on how to proceed without using the NUMA node information which Mark did not like to be used.

Quoted 5 lines

The only way to know which device is on which node would be to look at the PCI topology (which is also the source of the NUMA node_id). We could do this manually in order to not depend on CONFIG_NUMA, but I would like to know if that is acceptable before respinning the patches.

That doesn't feel like it really addresses Mark's concerns -- it's just another way to get the information that isn't a first-class PMU topology description from firmware.

Now, I don't actually mind using the NUMA topology so much in the cases where it genuinely correlates with the PMU topology. My objection is more that we end up sticking everything on node 0 if !CONFIG_NUMA, which could result in working with an incorrect PMU topology and passing all of that through to userspace.

So I'd prefer either making the driver depend on NUMA, or at the very least failing to probe the PMU if we discover a socketed system and NUMA is not selected. Do either of those work as a compromise?

Will

#14 lore raw
Quoted 27 lines · Will Deacon
Quoted 10 lines · Jan Glauber
Quoted 4 lines · Will Deacon
Quoted 1 line · Jan Glauber

can you have a look at these patches?

Looks like Mark reviewed this last week -- are you planning to respin?

Yes, of course. I just had no time yet and I'm a bit lost on how to proceed without using the NUMA node information which Mark did not like to be used.

Quoted 5 lines

The only way to know which device is on which node would be to look at the PCI topology (which is also the source of the NUMA node_id). We could do this manually in order to not depend on CONFIG_NUMA, but I would like to know if that is acceptable before respinning the patches.

That doesn't feel like it really addresses Mark's concerns -- it's just another way to get the information that isn't a first-class PMU topology description from firmware.

Now, I don't actually mind using the NUMA topology so much in the cases where it genuinely correlates with the PMU topology. My objection is more that we end up sticking everything on node 0 if !CONFIG_NUMA, which could result in working with an incorrect PMU topology and passing all of that through to userspace.

Quoted 5 lines

So I'd prefer either making the driver depend on NUMA, or at the very least failing to probe the PMU if we discover a socketed system and NUMA is not selected. Do either of those work as a compromise?

Will

That sounds like a good compromise.

So I could do the following:

1) In the uncore setup check for CONFIG_NUMA, if set use the NUMA information to determine the device node

2) If CONFIG_NUMA is not set we check if we run on a socketed system

a) In that case we return an error and give a message that CONFIG_NUMA needs to be enabled
b) Otherwise we have a single node system and use node_id = 0

David noted that it would also be possible to extract the node id from the physical address of the device, but I'm not sure that classifies as 'first-class' topology description...

--Jan

#15 lore raw
Quoted 38 lines · Jan Glauber
Quoted 27 lines · Will Deacon
Quoted 10 lines · Jan Glauber
Quoted 4 lines · Will Deacon
Quoted 1 line · Jan Glauber

can you have a look at these patches?

Looks like Mark reviewed this last week -- are you planning to respin?

Yes, of course. I just had no time yet and I'm a bit lost on how to proceed without using the NUMA node information which Mark did not like to be used.

Quoted 5 lines

The only way to know which device is on which node would be to look at the PCI topology (which is also the source of the NUMA node_id). We could do this manually in order to not depend on CONFIG_NUMA, but I would like to know if that is acceptable before respinning the patches.

That doesn't feel like it really addresses Mark's concerns -- it's just another way to get the information that isn't a first-class PMU topology description from firmware.

Now, I don't actually mind using the NUMA topology so much in the cases where it genuinely correlates with the PMU topology. My objection is more that we end up sticking everything on node 0 if !CONFIG_NUMA, which could result in working with an incorrect PMU topology and passing all of that through to userspace.

Quoted 5 lines

So I'd prefer either making the driver depend on NUMA, or at the very least failing to probe the PMU if we discover a socketed system and NUMA is not selected. Do either of those work as a compromise?

Will

That sounds like a good compromise.

So I could do the following:

Quoted 8 lines

1) In the uncore setup check for CONFIG_NUMA, if set use the NUMA information to determine the device node

2) If CONFIG_NUMA is not set we check if we run on a socketed system

a) In that case we return an error and give a message that CONFIG_NUMA needs to be enabled
b) Otherwise we have a single node system and use node_id = 0

That sounds sensible to me. How do you "check if we run on a socketed system"? My assumption would be that you could figure this out from the firmware tables?

Quoted 3 lines

David noted that it would also be possible to extract the node id from the physical address of the device, but I'm not sure that classifies as 'first-class' topology description...

I'd rather avoid this sort of probing, as it inevitably breaks when it sees new hardware that doesn't follow the unwritten assumptions of the old hardware.

Will

#16 lore raw

On Tue, Apr 26, 2016 at 02:53:54PM +0100, Will Deacon wrote:

[...]

Quoted 10 lines
Quoted 10 lines

That sounds like a good compromise.

So I could do the following:

1) In the uncore setup check for CONFIG_NUMA, if set use the NUMA information to determine the device node

2) If CONFIG_NUMA is not set we check if we run on a socketed system

Quoted 7 lines
Quoted 3 lines

a) In that case we return an error and give a message that CONFIG_NUMA needs to be enabled
b) Otherwise we have a single node system and use node_id = 0

That sounds sensible to me. How do you "check if we run on a socketed system"? My assumption would be that you could figure this out from the firmware tables?

There are probably multiple ways to detect a socketed system, with some quite hardware specific. I would like to avoid parsing DT (and ACPI) though, if possible.

A generic approach would be to do a query of the multiprocessor affinity register (MPIDR_EL1) on all CPUs. The AFF2 part (bits 23:16) contains the socket number on ThunderX. If this is non-zero on any CPU I would assume a socketed system.

Would that be feasible?

thanks,
Jan

maintainer
#17 lore raw
Quoted 26 lines · Jan Glauber

On Tue, Apr 26, 2016 at 02:53:54PM +0100, Will Deacon wrote:

[...]

Quoted 10 lines
Quoted 10 lines

That sounds like a good compromise.

So I could do the following:

1) In the uncore setup check for CONFIG_NUMA, if set use the NUMA information to determine the device node

2) If CONFIG_NUMA is not set we check if we run on a socketed system

Quoted 7 lines
Quoted 3 lines

a) In that case we return an error and give a message that CONFIG_NUMA needs to be enabled
b) Otherwise we have a single node system and use node_id = 0

That sounds sensible to me. How do you "check if we run on a socketed system"? My assumption would be that you could figure this out from the firmware tables?

There are probably multiple ways to detect a socketed system, with some quite hardware specific. I would like to avoid parsing DT (and ACPI) though, if possible.

Quoted 6 lines

A generic approach would be to do a query of the multiprocessor affinity register (MPIDR_EL1) on all CPUs. The AFF2 part (bits 23:16) contains the socket number on ThunderX. If this is non-zero on any CPU I would assume a socketed system.

Would that be feasible?

As with checking the physical address of a peripheral, this is an unwritten assumption, and I suspect that similarly, it will inevitably break (e.g. if Aff3 becomes used).

If you expect kernels relevant to your platform to have NUMA support, you can simply depend on NUMA to determine whether or not you have NUMA nodes.

Regarding relying on NUMA nodes, I have two concerns:

In general a NUMA node is not necessarily a socket, as you can have NUMA properties even within a socket. If you can guarantee that for your platform NUMA nodes will always be sockets, then I guess using NUMA nodes is ok, though I imagine that as with the physical address map and organisation of CPU IDs, that's difficult to have set in stone.

Linux NUMA node IDs are arbitrary tokens, and may not necessarily idmap to documented socket IDs for your platform (even if they happen to today). If you're happy to have users figure out how those IDs map to clusters, that's fine, but otherwise you need to expose additional information such that users get what they expect (at which point, if you have said information we probably don't need NUMA information).

Thanks,
Mark.

#21 lore raw
In reply to Jan Glauber

Hi Jan,

Quoted 9 lines · Jan Glauber

This patch series provides access to various counters on the ThunderX SOC.

For details of the uncore implementation see patch #1.

Patches #2-5 add the various ThunderX specific PMUs.

As suggested I've put the files under drivers/perf/uncore. I would prefer this location over drivers/bus because not all of the uncore drivers are bus related.

What's the status of these patches? Were you planning to send a new version?

Will

#22 lore raw
Quoted 9 lines · Will Deacon

Hi Jan,

Quoted 6 lines · Jan Glauber

This patch series provides access to various counters on the ThunderX SOC.

For details of the uncore implementation see patch #1.

Patches #2-5 add the various ThunderX specific PMUs.

Quoted 8 lines
Quoted 3 lines

As suggested I've put the files under drivers/perf/uncore. I would prefer this location over drivers/bus because not all of the uncore drivers are bus related.

What's the status of these patches? Were you planning to send a new version?

Will

Hi Will,

I was half-way through with addressing Mark's review comments when got side-tracked.

The principle question these patches raised remains open though in my opinion, how to determine the socket a device belongs to.

There is no first-class interface to ask a device or the firmware which socket the device lives on.

The options I see are:
A) Using NUMA node information, depends on CONFIG_NUMA
B) Decoding the socket bits of the PCI BAR address
C) Using PCI topology information

A is what I tried, but I agree that depending on CONFIG_NUMA is not a good solution. B would be easy but looks not very future-proof. So option C is what is left...

thanks,
Jan

#23 lore raw
Quoted 24 lines · Jan Glauber
Quoted 5 lines · Will Deacon
Quoted 4 lines · Jan Glauber

This patch series provides access to various counters on the ThunderX SOC.

For details of the uncore implementation see patch #1.

Quoted 8 lines
Quoted 5 lines

Patches #2-5 add the various ThunderX specific PMUs.

As suggested I've put the files under drivers/perf/uncore. I would prefer this location over drivers/bus because not all of the uncore drivers are bus related.

What's the status of these patches? Were you planning to send a new version?

I was half-way through with addressing Mark's review comments when got side-tracked.

The principle question these patches raised remains open though in my opinion, how to determine the socket a device belongs to.

There is no first-class interface to ask a device or the firmware which socket the device lives on.

Quoted 8 lines

The options I see are:
A) Using NUMA node information, depends on CONFIG_NUMA
B) Decoding the socket bits of the PCI BAR address
C) Using PCI topology information

A is what I tried, but I agree that depending on CONFIG_NUMA is not a good solution. B would be easy but looks not very future-proof. So option C is what is left...

Sorry to go full circle on this, but "depends on NUMA" sounds better than deriving NUMA topology from PCI to me. The only worry I have is if the NUMA information ends up being insufficient in the long-term, and we end up with a mixture of the three options above in order to figure out the PMU topology.

As long as you're happy that the PMU:NUMA topology remains 1:1, then I have no objections. The moment you need extra hacks on the side, we should probably drop the NUMA dependency altogether and figure it out some other way.

Will

#24 lore raw

Hi Jan,

Quoted 40 lines · Will Deacon
Quoted 24 lines · Jan Glauber
Quoted 5 lines · Will Deacon
Quoted 4 lines · Jan Glauber

This patch series provides access to various counters on the ThunderX SOC.

For details of the uncore implementation see patch #1.

Quoted 8 lines
Quoted 5 lines

Patches #2-5 add the various ThunderX specific PMUs.

As suggested I've put the files under drivers/perf/uncore. I would prefer this location over drivers/bus because not all of the uncore drivers are bus related.

What's the status of these patches? Were you planning to send a new version?

I was half-way through with addressing Mark's review comments when got side-tracked.

The principle question these patches raised remains open though in my opinion, how to determine the socket a device belongs to.

There is no first-class interface to ask a device or the firmware which socket the device lives on.

Quoted 8 lines

The options I see are:
A) Using NUMA node information, depends on CONFIG_NUMA
B) Decoding the socket bits of the PCI BAR address
C) Using PCI topology information

A is what I tried, but I agree that depending on CONFIG_NUMA is not a good solution. B would be easy but looks not very future-proof. So option C is what is left...

Sorry to go full circle on this, but "depends on NUMA" sounds better than deriving NUMA topology from PCI to me. The only worry I have is if the NUMA information ends up being insufficient in the long-term, and we end up with a mixture of the three options above in order to figure out the PMU topology.

Quoted 4 lines

As long as you're happy that the PMU:NUMA topology remains 1:1, then I have no objections. The moment you need extra hacks on the side, we should probably drop the NUMA dependency altogether and figure it out some other way.

Any news on this series, or did I miss a v3? I was hoping to have this in for 4.9, but it seems to have stalled :(

Will

#25 lore raw
Quoted 48 lines · Will Deacon

Hi Jan,

Quoted 40 lines · Will Deacon
Quoted 24 lines · Jan Glauber
Quoted 5 lines · Will Deacon
Quoted 4 lines · Jan Glauber

This patch series provides access to various counters on the ThunderX SOC.

For details of the uncore implementation see patch #1.

Quoted 8 lines
Quoted 5 lines

Patches #2-5 add the various ThunderX specific PMUs.

As suggested I've put the files under drivers/perf/uncore. I would prefer this location over drivers/bus because not all of the uncore drivers are bus related.

What's the status of these patches? Were you planning to send a new version?

I was half-way through with addressing Mark's review comments when got side-tracked.

The principle question these patches raised remains open though in my opinion, how to determine the socket a device belongs to.

There is no first-class interface to ask a device or the firmware which socket the device lives on.

Quoted 8 lines

The options I see are:
A) Using NUMA node information, depends on CONFIG_NUMA
B) Decoding the socket bits of the PCI BAR address
C) Using PCI topology information

A is what I tried, but I agree that depending on CONFIG_NUMA is not a good solution. B would be easy but looks not very future-proof. So option C is what is left...

Sorry to go full circle on this, but "depends on NUMA" sounds better than deriving NUMA topology from PCI to me. The only worry I have is if the NUMA information ends up being insufficient in the long-term, and we end up with a mixture of the three options above in order to figure out the PMU topology.

Quoted 4 lines

As long as you're happy that the PMU:NUMA topology remains 1:1, then I have no objections. The moment you need extra hacks on the side, we should probably drop the NUMA dependency altogether and figure it out some other way.

Quoted 4 lines

Any news on this series, or did I miss a v3? I was hoping to have this in for 4.9, but it seems to have stalled :(

Will

No news, I'm afraid it is stalled on my side :( I'll try to get back to it, but not for 4.9.

Jan