Skip to contentSkip to conversation

ARM perf events support v5

PATCH New Jamie Iles 7 participants 38 messages Jan 14, 2010 – Feb 5, 2010

Subsystems (4)
lore
Share & tools
lore

Jamie Iles

author
#0 lore raw

Here is the 5th revision of the ARM performance events support. This initially targets software events on all platforms and hardware events on v6 platforms with hooks for later platforms to be added later.

Changes since the previous revison are:
- compile fixes for systems without a pmu.
- remove mutex from pmu.c and replace with bitset based lock
- removal of BUG()'s and replace with warnings

Also required are:
ARM: 5866/1: arm ptrace: use unsigned types for kernel pt_regs sched/perf: Make sure irqs are disabled for perf_event_task_sched_in()

Both of these can be found in tip/master.

Jamie Iles (5):
arm: provide a mechanism to reserve performance counters arm/oprofile: reserve the PMU when starting
arm: use the spinlocked, generic atomic64 support
arm: enable support for software perf events arm/perfevents: implement perf event support for ARMv6

 arch/arm/Kconfig                        |   16 +
 arch/arm/include/asm/atomic.h           |    4 +
 arch/arm/include/asm/perf_event.h       |   31 +
 arch/arm/include/asm/pmu.h              |   75 ++
 arch/arm/kernel/Makefile                |    2 +
 arch/arm/kernel/perf_event.c            | 1342 +++++++++++++++++++++++++++++++
 arch/arm/kernel/pmu.c                   |  105 +++
 arch/arm/mm/fault.c                     |    7 +
 arch/arm/oprofile/op_model_arm11_core.c |    4 +-
 arch/arm/oprofile/op_model_arm11_core.h |    4 +-
 arch/arm/oprofile/op_model_mpcore.c     |   42 +-
 arch/arm/oprofile/op_model_v6.c         |   30 +-
 arch/arm/oprofile/op_model_v7.c         |   30 +-
 arch/arm/oprofile/op_model_v7.h         |    4 +-
 arch/arm/oprofile/op_model_xscale.c     |   35 +-
 15 files changed, 1667 insertions(+), 64 deletions(-)
author
#1 lore raw

PATCH 1/5 arm: provide a mechanism to reserve performance counters

To add support for perf events and to allow the hardware counters to be shared with oprofile, we need a way to reserve access to the pmu (performance monitor unit).

---
 arch/arm/Kconfig           |    5 ++
 arch/arm/include/asm/pmu.h |   75 +++++++++++++++++++++++++++++++
 arch/arm/kernel/Makefile   |    1 +
 arch/arm/kernel/pmu.c      |  105 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 186 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/pmu.h
 create mode 100644 arch/arm/kernel/pmu.c
arch/arm/Kconfig +5 -0
index c2238cd..31d52ed 100644
@@ -866,6 +866,11 @@ config XSCALE_PMU
 	depends on CPU_XSCALE && !XSCALE_PMU_TIMER
 	default y
 
+config CPU_HAS_PMU
+	depends on CPU_V6 || CPU_V7 || XSCALE_PMU
+	default y
+	bool
+
 if !MMU
 source "arch/arm/Kconfig-nommu"
 endif
arch/arm/include/asm/pmu.h new file +75 -0

75 lines not on this page · raw message

arch/arm/kernel/Makefile +1 -0
index dd00f74..216890d 100644
@@ -46,6 +46,7 @@ obj-$(CONFIG_CPU_XSCALE)	+= xscale-cp0.o
 obj-$(CONFIG_CPU_XSC3)		+= xscale-cp0.o
 obj-$(CONFIG_CPU_MOHAWK)	+= xscale-cp0.o
 obj-$(CONFIG_IWMMXT)		+= iwmmxt.o
+obj-$(CONFIG_CPU_HAS_PMU)	+= pmu.o
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
 
 ifneq ($(CONFIG_ARCH_EBSA110),y)
arch/arm/kernel/pmu.c new file +105 -0

105 lines not on this page · raw message

Signature · 1 line
1.6.5.4
author
#2 lore raw

PATCH 2/5 arm/oprofile: reserve the PMU when starting

Make sure that we have access to the performance counters and that they aren't being used by perf events or anything else.

Cc Will Deacon <[email protected]>
Cc Jean Pihet <[email protected]>
---
 arch/arm/oprofile/op_model_arm11_core.c |    4 +-
 arch/arm/oprofile/op_model_arm11_core.h |    4 +-
 arch/arm/oprofile/op_model_mpcore.c     |   42 ++++++++++++++++--------------
 arch/arm/oprofile/op_model_v6.c         |   30 ++++++++++++++--------
 arch/arm/oprofile/op_model_v7.c         |   30 ++++++++++++++--------
 arch/arm/oprofile/op_model_v7.h         |    4 +-
 arch/arm/oprofile/op_model_xscale.c     |   35 ++++++++++++++-----------
 7 files changed, 85 insertions(+), 64 deletions(-)
arch/arm/oprofile/op_model_arm11_core.c +2 -2
index ad80752..ef3e265 100644
@@ -132,7 +132,7 @@ static irqreturn_t arm11_pmu_interrupt(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
-int arm11_request_interrupts(int *irqs, int nr)
+int arm11_request_interrupts(const int *irqs, int nr)
 {
 	unsigned int i;
 	int ret = 0;
@@ -153,7 +153,7 @@ int arm11_request_interrupts(int *irqs, int nr)
 	return ret;
 }
 
-void arm11_release_interrupts(int *irqs, int nr)
+void arm11_release_interrupts(const int *irqs, int nr)
 {
 	unsigned int i;
 
arch/arm/oprofile/op_model_arm11_core.h +2 -2
index 6f8538e..1902b99 100644
@@ -39,7 +39,7 @@
 int arm11_setup_pmu(void);
 int arm11_start_pmu(void);
 int arm11_stop_pmu(void);
-int arm11_request_interrupts(int *, int);
-void arm11_release_interrupts(int *, int);
+int arm11_request_interrupts(const int *, int);
+void arm11_release_interrupts(const int *, int);
 
 #endif
arch/arm/oprofile/op_model_mpcore.c +22 -20

88 lines not on this page · raw message

arch/arm/oprofile/op_model_v6.c +19 -11
index f7d2ec5..a22357a 100644
@@ -19,39 +19,47 @@
 /* #define DEBUG */
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/sched.h>
 #include <linux/oprofile.h>
 #include <linux/interrupt.h>
 #include <asm/irq.h>
 #include <asm/system.h>
+#include <asm/pmu.h>
 
 #include "op_counter.h"
 #include "op_arm_model.h"
 #include "op_model_arm11_core.h"
 
-static int irqs[] = {
-#ifdef CONFIG_ARCH_OMAP2
-	3,
-#endif
-#ifdef CONFIG_ARCH_BCMRING
-	IRQ_PMUIRQ, /* for BCMRING, ARM PMU interrupt is 43 */
-#endif
-};
+static const struct pmu_irqs *pmu_irqs;
 
 static void armv6_pmu_stop(void)
 {
 	arm11_stop_pmu();
-	arm11_release_interrupts(irqs, ARRAY_SIZE(irqs));
+	arm11_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
+	release_pmu(pmu_irqs);
+	pmu_irqs = NULL;
 }
 
 static int armv6_pmu_start(void)
 {
 	int ret;
 
-	ret = arm11_request_interrupts(irqs, ARRAY_SIZE(irqs));
-	if (ret >= 0)
+	pmu_irqs = reserve_pmu();
+	if (IS_ERR(pmu_irqs)) {
+		ret = PTR_ERR(pmu_irqs);
+		goto out;
+	}
+
+	ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
+	if (ret >= 0) {
 		ret = arm11_start_pmu();
+	} else {
+		release_pmu(pmu_irqs);
+		pmu_irqs = NULL;
+	}
 
+out:
 	return ret;
 }
 
arch/arm/oprofile/op_model_v7.c +19 -11
index 2088a6c..8642d08 100644
@@ -11,11 +11,14 @@
  */
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/oprofile.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/smp.h>
 
+#include <asm/pmu.h>
+
 #include "op_counter.h"
 #include "op_arm_model.h"
 #include "op_model_v7.h"
@@ -295,7 +298,7 @@ static irqreturn_t armv7_pmnc_interrupt(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
-int armv7_request_interrupts(int *irqs, int nr)
+int armv7_request_interrupts(const int *irqs, int nr)
 {
 	unsigned int i;
 	int ret = 0;
@@ -318,7 +321,7 @@ int armv7_request_interrupts(int *irqs, int nr)
 	return ret;
 }
 
-void armv7_release_interrupts(int *irqs, int nr)
+void armv7_release_interrupts(const int *irqs, int nr)
 {
 	unsigned int i;
 
@@ -362,12 +365,7 @@ static void armv7_pmnc_dump_regs(void)
 }
 #endif
 
-
-static int irqs[] = {
-#ifdef CONFIG_ARCH_OMAP3
-	INT_34XX_BENCH_MPU_EMUL,
-#endif
-};
+static const struct pmu_irqs *pmu_irqs;
 
 static void armv7_pmnc_stop(void)
 {
@@ -375,19 +373,29 @@ static void armv7_pmnc_stop(void)
 	armv7_pmnc_dump_regs();
 #endif
 	armv7_stop_pmnc();
-	armv7_release_interrupts(irqs, ARRAY_SIZE(irqs));
+	armv7_release_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
+	release_pmu(pmu_irqs);
+	pmu_irqs = NULL;
 }
 
 static int armv7_pmnc_start(void)
 {
 	int ret;
 
+	pmu_irqs = reserve_pmu();
+	if (IS_ERR(pmu_irqs))
+		return PTR_ERR(pmu_irqs);
+
 #ifdef DEBUG
 	armv7_pmnc_dump_regs();
 #endif
-	ret = armv7_request_interrupts(irqs, ARRAY_SIZE(irqs));
-	if (ret >= 0)
+	ret = armv7_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
+	if (ret >= 0) {
 		armv7_start_pmnc();
+	} else {
+		release_pmu(pmu_irqs);
+		pmu_irqs = NULL;
+	}
 
 	return ret;
 }
arch/arm/oprofile/op_model_v7.h +2 -2
index 0e19bcc..9ca334b 100644
@@ -97,7 +97,7 @@
 int armv7_setup_pmu(void);
 int armv7_start_pmu(void);
 int armv7_stop_pmu(void);
-int armv7_request_interrupts(int *, int);
-void armv7_release_interrupts(int *, int);
+int armv7_request_interrupts(const int *, int);
+void armv7_release_interrupts(const int *, int);
 
 #endif
arch/arm/oprofile/op_model_xscale.c +19 -16
index 724ab9c..1d34a02 100644
@@ -17,12 +17,14 @@
 /* #define DEBUG */
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/sched.h>
 #include <linux/oprofile.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 
 #include <asm/cputype.h>
+#include <asm/pmu.h>
 
 #include "op_counter.h"
 #include "op_arm_model.h"
@@ -33,17 +35,6 @@
 #define	PMU_RESET	(CCNT_RESET | PMN_RESET)
 #define PMU_CNT64	0x008	/* Make CCNT count every 64th cycle */
 
-/* TODO do runtime detection */
-#ifdef CONFIG_ARCH_IOP32X
-#define XSCALE_PMU_IRQ  IRQ_IOP32X_CORE_PMU
-#endif
-#ifdef CONFIG_ARCH_IOP33X
-#define XSCALE_PMU_IRQ  IRQ_IOP33X_CORE_PMU
-#endif
-#ifdef CONFIG_ARCH_PXA
-#define XSCALE_PMU_IRQ  IRQ_PMU
-#endif
-
 /*
  * Different types of events that can be counted by the XScale PMU
  * as used by Oprofile userspace. Here primarily for documentation
@@ -367,6 +358,8 @@ static irqreturn_t xscale_pmu_interrupt(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
+static const struct pmu_irqs *pmu_irqs;
+
 static void xscale_pmu_stop(void)
 {
 	u32 pmnc = read_pmnc();
@@ -374,20 +367,30 @@ static void xscale_pmu_stop(void)
 	pmnc &= ~PMU_ENABLE;
 	write_pmnc(pmnc);
 
-	free_irq(XSCALE_PMU_IRQ, results);
+	free_irq(pmu_irqs->irqs[0], results);
+	release_pmu(pmu_irqs);
+	pmu_irqs = NULL;
 }
 
 static int xscale_pmu_start(void)
 {
 	int ret;
-	u32 pmnc = read_pmnc();
+	u32 pmnc;
+
+	pmu_irqs = reserve_pmu();
+	if (IS_ERR(pmu_irqs))
+		return PTR_ERR(pmu_irqs);
+
+	pmnc = read_pmnc();
 
-	ret = request_irq(XSCALE_PMU_IRQ, xscale_pmu_interrupt, IRQF_DISABLED,
-			"XScale PMU", (void *)results);
+	ret = request_irq(pmu_irqs->irqs[0], xscale_pmu_interrupt,
+			  IRQF_DISABLED, "XScale PMU", (void *)results);
 
 	if (ret < 0) {
 		printk(KERN_ERR "oprofile: unable to request IRQ%d for XScale PMU\n",
-			XSCALE_PMU_IRQ);
+		       pmu_irqs->irqs[0]);
+		release_pmu(pmu_irqs);
+		pmu_irqs = NULL;
 		return ret;
 	}
 
Signature · 1 line
1.6.5.4
author
#3 lore raw

PATCH 3/5 arm: use the spinlocked, generic atomic64 support

perf events require that we can support atomic64's. There is a generic, spinlocked version that we can use until we have proper hardware support.

---
 arch/arm/Kconfig              |    1 +
 arch/arm/include/asm/atomic.h |    4 ++++
 2 files changed, 5 insertions(+), 0 deletions(-)
arch/arm/Kconfig +1 -0
index 31d52ed..293a879 100644
@@ -20,6 +20,7 @@ config ARM
 	select HAVE_GENERIC_DMA_COHERENT
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZO
+	select GENERIC_ATOMIC64
 	help
 	  The ARM series is a line of low-power-consumption RISC chip designs
 	  licensed by ARM Ltd and targeted at embedded applications and
arch/arm/include/asm/atomic.h +4 -0
index d0daeab..ff286a8 100644
@@ -15,6 +15,10 @@
 #include <linux/types.h>
 #include <asm/system.h>
 
+#ifdef CONFIG_GENERIC_ATOMIC64
+#include <asm-generic/atomic64.h>
+#endif
+
 #define ATOMIC_INIT(i)	{ (i) }
 
 #ifdef __KERNEL__
Signature · 1 line
1.6.5.4
author
#4 lore raw

PATCH 4/5 arm: enable support for software perf events

The perf events subsystem allows counting of both hardware and software events. This patch implements the bare minimum for software performance events.

Cc Peter Zijlstra <[email protected]>
Cc Ingo Molnar <[email protected]>
---
 arch/arm/Kconfig                  |    2 ++
 arch/arm/include/asm/perf_event.h |   31 +++++++++++++++++++++++++++++++
 arch/arm/mm/fault.c               |    7 +++++++
 3 files changed, 40 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/perf_event.h
arch/arm/Kconfig +2 -0
index 293a879..72646b2 100644
@@ -21,6 +21,8 @@ config ARM
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZO
 	select GENERIC_ATOMIC64
+	select HAVE_PERF_EVENTS
+	select PERF_USE_VMALLOC
 	help
 	  The ARM series is a line of low-power-consumption RISC chip designs
 	  licensed by ARM Ltd and targeted at embedded applications and
arch/arm/include/asm/perf_event.h new file +31 -0
new file mode 100644
index 0000000..49e3049
@@ -0,0 +1,31 @@
+/*
+ *  linux/arch/arm/include/asm/perf_event.h
+ *
+ *  Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ARM_PERF_EVENT_H__
+#define __ARM_PERF_EVENT_H__
+
+/*
+ * NOP: on *most* (read: all supported) ARM platforms, the performance
+ * counter interrupts are regular interrupts and not an NMI. This
+ * means that when we receive the interrupt we can call
+ * perf_event_do_pending() that handles all of the work with
+ * interrupts enabled.
+ */
+static inline void
+set_perf_event_pending(void)
+{
+}
+
+/* ARM performance counters start from 1 (in the cp15 accesses) so use the
+ * same indexes here for consistency. */
+#define PERF_EVENT_INDEX_OFFSET 1
+
+#endif /* __ARM_PERF_EVENT_H__ */
arch/arm/mm/fault.c +7 -0
index 10e0680..9d40c34 100644
@@ -18,6 +18,7 @@
 #include <linux/page-flags.h>
 #include <linux/sched.h>
 #include <linux/highmem.h>
+#include <linux/perf_event.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -302,6 +303,12 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	fault = __do_page_fault(mm, addr, fsr, tsk);
 	up_read(&mm->mmap_sem);
 
+	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, addr);
+	if (fault & VM_FAULT_MAJOR)
+		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, regs, addr);
+	else if (fault & VM_FAULT_MINOR)
+		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, regs, addr);
+
 	/*
 	 * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR
 	 */
Signature · 1 line
1.6.5.4
author
#5 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

This patch implements support for ARMv6 performance counters in the Linux performance events subsystem. ARMv6 architectures that have the performance counters should enable HW_PERF_EVENTS and define the interrupts for the counters in arch/arm/kernel/perf_event.c

This implementation also provides an ARM PMU abstraction layer to allow ARMv7 and others to be supported in the future by adding new a 'struct arm_pmu'.

Cc Peter Zijlstra <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Jean Pihet <[email protected]>
Cc Will Deacon <[email protected]>
---
 arch/arm/Kconfig             |    8 +
 arch/arm/kernel/Makefile     |    1 +
 arch/arm/kernel/perf_event.c | 1342 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1351 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/kernel/perf_event.c
arch/arm/Kconfig +8 -0
index 72646b2..6036e63 100644
@@ -1178,6 +1178,14 @@ config HIGHPTE
 	depends on HIGHMEM
 	depends on !OUTER_CACHE
 
+config HW_PERF_EVENTS
+	bool "Enable hardware performance counter support for perf events"
+	depends on PERF_EVENTS && CPU_HAS_PMU && CPU_V6
+	default y
+	help
+	  Enable hardware performance counter support for perf events. If
+	  disabled, perf events will use software events only.
+
 source "mm/Kconfig"
 
 config LEDS
arch/arm/kernel/Makefile +1 -0
index 216890d..c76e6d2 100644
@@ -47,6 +47,7 @@ obj-$(CONFIG_CPU_XSC3)		+= xscale-cp0.o
 obj-$(CONFIG_CPU_MOHAWK)	+= xscale-cp0.o
 obj-$(CONFIG_IWMMXT)		+= iwmmxt.o
 obj-$(CONFIG_CPU_HAS_PMU)	+= pmu.o
+obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
 
 ifneq ($(CONFIG_ARCH_EBSA110),y)
arch/arm/kernel/perf_event.c new file +1342 -0

1,342 lines not on this page · raw message

Signature · 1 line
1.6.5.4
#6 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Quoted 4 lines · Jamie Iles

This patch implements support for ARMv6 performance counters in the Linux performance events subsystem. ARMv6 architectures that have the performance counters should enable HW_PERF_EVENTS and define the interrupts for the counters in arch/arm/kernel/perf_event.c

The commit message needs a tweak before submitting as the IRQs are listed in arch/arm/kernel/pmu.c now rather than perf_event.c.

Quoted 23 lines
arch/arm/kernel/perf_event.c new file +23 -0
+static int __init
+init_hw_perf_events(void)
+{
+#define CPUID_MASK	0xFFF0
+	unsigned long cpuid = read_cpuid_id() & CPUID_MASK;
+
+	switch (cpuid) {
+	case 0xB360:	/* ARM1136 */
+	case 0xB560:	/* ARM1156 */
+	case 0xB760:	/* ARM1176 */
+		armpmu = &armv6pmu;
+		memcpy(armpmu_perf_cache_map, armv6_perf_cache_map,
+				sizeof(armv6_perf_cache_map));
+		perf_max_events	= armv6pmu.num_events;
+		break;
+	case 0xB020:	/* ARM11mpcore */
+		armpmu = &armv6mpcore_pmu;
+		memcpy(armpmu_perf_cache_map, armv6mpcore_perf_cache_map,
+				sizeof(armv6mpcore_perf_cache_map));
+		perf_max_events = armv6mpcore_pmu.num_events;
+		break;
+	default:
+		pr_info("no hardware support available\n");

arch/arm/kernel/perf_event.c line 1208

Quoted 10 lines
arch/arm/kernel/perf_event.c new file +10 -0
+		perf_max_events = -1;
+	}
+
+	if (armpmu)
+		pr_info("enabled with %s PMU driver\n",
+				armpmu->name);
+
+	return 0;
+}
+arch_initcall(init_hw_perf_events);

Given the difficulty in determining the CPU type 100%, this should be changed to:

	unsigned long cpuid = read_cpuid_id();
	unsigned long implementor = (cpuid & 0xFF000000) >> 24;
	unsigned long part_number = (cpuid & 0xFFF0);
	
	/* We only support ARM CPUs implemented by ARM at the moment. */
	if (implementor == 0x41) {
		switch (part_number) {
		case 0xB360:
		case 0xB560:
			etc

Jamie

#7 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Hi Jamie,

Quoted 13 lines · Jamie Iles

Given the difficulty in determining the CPU type 100%, this should be changed to:

	unsigned long cpuid = read_cpuid_id();
	unsigned long implementor = (cpuid & 0xFF000000) >> 24;
	unsigned long part_number = (cpuid & 0xFFF0);

	/* We only support ARM CPUs implemented by ARM at the moment. */
	if (implementor == 0x41) {
		switch (part_number) {
		case 0xB360:
		case 0xB560:
			etc

Whilst I understand that the whole cpuid thing is a complete mess [I saw the lkml posts yesterday], I'm not sure this is necessary for v7 cores. For v7, the PMU is part of the architecture and so *must* be implemented in the way described in the ARM ARM [Chapter 9], regardless of the implementer.

However, for v6 you're right - checking that ARM is the implementer is a sensible thing to do. This does rely on the implementer setting those bits correctly though :)

Additionally, it's quite possible for an implementer to extend the hardware counters on a v7 SoC. This means that you would have the PMU as described in the ARM ARM, but then additional counters, perhaps outside the core that can be accessed in a different way. In this case, switching on the implementer ID is essential to determine extra features, but the base features can be assumed to be present.

All food for thought.

Cheers,

Will

#8 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Hi Will,

Thanks for confirming this!

Quoted 23 lines · Will Deacon
Quoted 13 lines

Given the difficulty in determining the CPU type 100%, this should be changed to:

	unsigned long cpuid = read_cpuid_id();
	unsigned long implementor = (cpuid & 0xFF000000) >> 24;
	unsigned long part_number = (cpuid & 0xFFF0);

	/* We only support ARM CPUs implemented by ARM at the moment. */
	if (implementor == 0x41) {
		switch (part_number) {
		case 0xB360:
		case 0xB560:
			etc

Whilst I understand that the whole cpuid thing is a complete mess [I saw the lkml posts yesterday], I'm not sure this is necessary for v7 cores. For v7, the PMU is part of the architecture and so *must* be implemented in the way described in the ARM ARM [Chapter 9], regardless of the implementer.

However, for v6 you're right - checking that ARM is the implementer is a sensible thing to do. This does rely on the implementer setting those bits correctly though :)

Quoted 6 lines

Additionally, it's quite possible for an implementer to extend the hardware counters on a v7 SoC. This means that you would have the PMU as described in the ARM ARM, but then additional counters, perhaps outside the core that can be accessed in a different way. In this case, switching on the implementer ID is essential to determine extra features, but the base features can be assumed to be present.

Ok, I think that's fine then because in Jean's patch to add v7 support we do ARMv6 first and if it doesn't match then do v7 so we should end up with the lowest common denominator. Initially I think we should target just the standard ARM counters in ARM Ltd chips then we can add in support for additional counters and implementors when needed.

Jamie

#9 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

In reply to Jamie Iles
Quoted 19 lines · Will Deacon

Hi Jamie,

Quoted 13 lines · Jamie Iles

Given the difficulty in determining the CPU type 100%, this should be changed to:

	unsigned long cpuid = read_cpuid_id();
	unsigned long implementor = (cpuid & 0xFF000000) >> 24;
	unsigned long part_number = (cpuid & 0xFFF0);

	/* We only support ARM CPUs implemented by ARM at the moment. */
	if (implementor == 0x41) {
		switch (part_number) {
		case 0xB360:
		case 0xB560:
			etc
Quoted 4 lines

Whilst I understand that the whole cpuid thing is a complete mess [I saw the lkml posts yesterday], I'm not sure this is necessary for v7 cores. For v7, the PMU is part of the architecture and so *must* be implemented in the way described in the ARM ARM [Chapter 9], regardless of the implementer.

This function is called whenever the PMU support is built in - and this is the first place a decision is made about how to handle stuff.

Merely checking the part number without checking the implementer is nonsense - the part number is defined by the implmenter, not ARM, so the part number can only be interpreted with knowledge of the implementer.

So, when v7 gets added, checking the main ID register is the wrong thing to do.

Given that cpu_architecture() appears to have been redefined to return the MMU architecture, we have no real way to properly determine if we have a v7 PMU present - in fact, the whole "are we v6 or v7 or something later" question seems to be extremely muddy and indeterminant.

So I don't think even checking cpu_architecture() == CPU_ARCH_ARMv7 is the right thing either.

#10 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Hi Russell,

Quoted 7 lines · Russell King

This function is called whenever the PMU support is built in - and this is the first place a decision is made about how to handle stuff.

Merely checking the part number without checking the implementer is nonsense - the part number is defined by the implmenter, not ARM, so the part number can only be interpreted with knowledge of the implementer.

Perhaps, but if [somehow] we know we're on a v7 core, then we must have at least the PMU support defined by the architecture. We can then check the part ID and the implementer ID to determine any extra events.

Quoted 7 lines

So, when v7 gets added, checking the main ID register is the wrong thing to do.

Given that cpu_architecture() appears to have been redefined to return the MMU architecture, we have no real way to properly determine if we have a v7 PMU present - in fact, the whole "are we v6 or v7 or something later" question seems to be extremely muddy and indeterminant.

Right. Could we use the Debug ID register (DIDR[19:16]) instead? If it reads v7, we know how to talk to the PMU. If it reads v6, then if we haven't handled the core already, it's unsupported.

Quoted 2 lines

So I don't think even checking cpu_architecture() == CPU_ARCH_ARMv7 is the right thing either.

Indeed. That always catches me out!

Cheers,

Will

#11 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

In reply to Russell King - ARM Linux
Quoted 35 lines · On Thursday 21 January 2010 11:38:03 Russell King - ARM Linux wrote:
Quoted 17 lines · Will Deacon

Hi Jamie,

Quoted 13 lines · Jamie Iles

Given the difficulty in determining the CPU type 100%, this should be changed to:

	unsigned long cpuid = read_cpuid_id();
	unsigned long implementor = (cpuid & 0xFF000000) >> 24;
	unsigned long part_number = (cpuid & 0xFFF0);

	/* We only support ARM CPUs implemented by ARM at the moment. */
	if (implementor == 0x41) {
		switch (part_number) {
		case 0xB360:
		case 0xB560:
			etc
Quoted 5 lines

Whilst I understand that the whole cpuid thing is a complete mess [I saw the lkml posts yesterday], I'm not sure this is necessary for v7 cores. For v7, the PMU is part of the architecture and so *must* be implemented in the way described in the ARM ARM [Chapter 9], regardless of the implementer.

This function is called whenever the PMU support is built in - and this is the first place a decision is made about how to handle stuff.

Merely checking the part number without checking the implementer is nonsense - the part number is defined by the implmenter, not ARM, so the part number can only be interpreted with knowledge of the implementer.

So, when v7 gets added, checking the main ID register is the wrong thing to do.

Quoted 7 lines

Given that cpu_architecture() appears to have been redefined to return the MMU architecture, we have no real way to properly determine if we have a v7 PMU present - in fact, the whole "are we v6 or v7 or something later" question seems to be extremely muddy and indeterminant.

So I don't think even checking cpu_architecture() == CPU_ARCH_ARMv7 is the right thing either.

Agree. Here is the latest version of the detection code, after merging Jamie's latest version:

        unsigned long cpuid = read_cpuid_id() & CPUID_MASK;

        switch (cpuid) {
        case 0xB360:    /* ARM1136 */
        case 0xB560:    /* ARM1156 */
        case 0xB760:    /* ARM1176 */
	    ...
                break;
        case 0xB020:    /* ARM11mpcore */
	    ...
                break;
        case 0xC080:    /* Cortex-A8 */
	    ...
                break;
        case 0xC090:    /* Cortex-A9 */
	    ...
                break;
        default:
                pr_info("no hardware support available\n");
                perf_max_events = -1;
       }
       ...

Is that OK if we just add 'if (implementor == 0x41) {' before the switch statement, as proposed above?

Jean

#12 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Quoted 69 lines · Jean Pihet
Quoted 35 lines · On Thursday 21 January 2010 11:38:03 Russell King - ARM Linux wrote:
Quoted 17 lines · Will Deacon

Hi Jamie,

Quoted 13 lines · Jamie Iles

Given the difficulty in determining the CPU type 100%, this should be changed to:

	unsigned long cpuid = read_cpuid_id();
	unsigned long implementor = (cpuid & 0xFF000000) >> 24;
	unsigned long part_number = (cpuid & 0xFFF0);

	/* We only support ARM CPUs implemented by ARM at the moment. */
	if (implementor == 0x41) {
		switch (part_number) {
		case 0xB360:
		case 0xB560:
			etc
Quoted 5 lines

Whilst I understand that the whole cpuid thing is a complete mess [I saw the lkml posts yesterday], I'm not sure this is necessary for v7 cores. For v7, the PMU is part of the architecture and so *must* be implemented in the way described in the ARM ARM [Chapter 9], regardless of the implementer.

This function is called whenever the PMU support is built in - and this is the first place a decision is made about how to handle stuff.

Merely checking the part number without checking the implementer is nonsense - the part number is defined by the implmenter, not ARM, so the part number can only be interpreted with knowledge of the implementer.

So, when v7 gets added, checking the main ID register is the wrong thing to do.

Quoted 7 lines

Given that cpu_architecture() appears to have been redefined to return the MMU architecture, we have no real way to properly determine if we have a v7 PMU present - in fact, the whole "are we v6 or v7 or something later" question seems to be extremely muddy and indeterminant.

So I don't think even checking cpu_architecture() == CPU_ARCH_ARMv7 is the right thing either.

Agree. Here is the latest version of the detection code, after merging Jamie's latest version:

        unsigned long cpuid = read_cpuid_id() & CPUID_MASK;

        switch (cpuid) {
        case 0xB360:    /* ARM1136 */
        case 0xB560:    /* ARM1156 */
        case 0xB760:    /* ARM1176 */
	    ...
                break;
        case 0xB020:    /* ARM11mpcore */
	    ...
                break;
        case 0xC080:    /* Cortex-A8 */
	    ...
                break;
        case 0xC090:    /* Cortex-A9 */
	    ...
                break;
        default:
                pr_info("no hardware support available\n");
                perf_max_events = -1;
       }
       ...
Quoted 2 lines

Is that OK if we just add 'if (implementor == 0x41) {' before the switch statement, as proposed above?

That sounds good to me. Are these patches ready for merging?

Jamie

#13 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Quoted 72 lines · On Thursday 21 January 2010 13:27:43 Jamie Iles wrote:
Quoted 71 lines · Jean Pihet
Quoted 35 lines · On Thursday 21 January 2010 11:38:03 Russell King - ARM Linux wrote:
Quoted 17 lines · Will Deacon

Hi Jamie,

Quoted 13 lines · Jamie Iles

Given the difficulty in determining the CPU type 100%, this should be changed to:

	unsigned long cpuid = read_cpuid_id();
	unsigned long implementor = (cpuid & 0xFF000000) >> 24;
	unsigned long part_number = (cpuid & 0xFFF0);

	/* We only support ARM CPUs implemented by ARM at the moment. */
	if (implementor == 0x41) {
		switch (part_number) {
		case 0xB360:
		case 0xB560:
			etc
Quoted 5 lines

Whilst I understand that the whole cpuid thing is a complete mess [I saw the lkml posts yesterday], I'm not sure this is necessary for v7 cores. For v7, the PMU is part of the architecture and so *must* be implemented in the way described in the ARM ARM [Chapter 9], regardless of the implementer.

This function is called whenever the PMU support is built in - and this is the first place a decision is made about how to handle stuff.

Merely checking the part number without checking the implementer is nonsense - the part number is defined by the implmenter, not ARM, so the part number can only be interpreted with knowledge of the implementer.

So, when v7 gets added, checking the main ID register is the wrong thing to do.

Quoted 8 lines

Given that cpu_architecture() appears to have been redefined to return the MMU architecture, we have no real way to properly determine if we have a v7 PMU present - in fact, the whole "are we v6 or v7 or something later" question seems to be extremely muddy and indeterminant.

So I don't think even checking cpu_architecture() == CPU_ARCH_ARMv7 is the right thing either.

Agree. Here is the latest version of the detection code, after merging Jamie's latest version:

        unsigned long cpuid = read_cpuid_id() & CPUID_MASK;

        switch (cpuid) {
        case 0xB360:    /* ARM1136 */
        case 0xB560:    /* ARM1156 */
        case 0xB760:    /* ARM1176 */
	    ...
                break;
        case 0xB020:    /* ARM11mpcore */
	    ...
                break;
        case 0xC080:    /* Cortex-A8 */
	    ...
                break;
        case 0xC090:    /* Cortex-A9 */
	    ...
                break;
        default:
                pr_info("no hardware support available\n");
                perf_max_events = -1;
       }
       ...
Quoted 4 lines
Quoted 2 lines

Is that OK if we just add 'if (implementor == 0x41) {' before the switch statement, as proposed above?

That sounds good to me. Are these patches ready for merging?

Yes the code is ready, testing it right now. I will rebase it on your latest version as soon as they are available.

Are you ok to post the patches to the ML and tp patchwork?

Quoted 1 line

Jamie

Jean

#14 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Quoted 8 lines · Jean Pihet
Quoted 4 lines
Quoted 2 lines

Is that OK if we just add 'if (implementor == 0x41) {' before the switch statement, as proposed above?

That sounds good to me. Are these patches ready for merging?

Yes the code is ready, testing it right now. I will rebase it on your latest version as soon as they are available.

Are you ok to post the patches to the ML and tp patchwork?

Updated patch below.

Jamie

arm/perfevents: implement perf event support for ARMv6

This patch implements support for ARMv6 performance counters in the Linux performance events subsystem. ARMv6 architectures that have the performance counters should enable HW_PERF_EVENTS to get hardware performance events support in addition to the software events.

Note: only ARM Ltd ARM cores are supported.

This implementation also provides an ARM PMU abstraction layer to allow ARMv7 and others to be supported in the future by adding new a 'struct arm_pmu'.

Cc Russell King - ARM Linux <[email protected]>
Cc Jean Pihet <[email protected]>
Cc Will Deacon <[email protected]>
---
 arch/arm/Kconfig             |    8 +
 arch/arm/kernel/Makefile     |    1 +
 arch/arm/kernel/perf_event.c | 1347 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1356 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/kernel/perf_event.c
arch/arm/Kconfig +8 -0
index 72646b2..6036e63 100644
@@ -1178,6 +1178,14 @@ config HIGHPTE
 	depends on HIGHMEM
 	depends on !OUTER_CACHE
 
+config HW_PERF_EVENTS
+	bool "Enable hardware performance counter support for perf events"
+	depends on PERF_EVENTS && CPU_HAS_PMU && CPU_V6
+	default y
+	help
+	  Enable hardware performance counter support for perf events. If
+	  disabled, perf events will use software events only.
+
 source "mm/Kconfig"
 
 config LEDS
arch/arm/kernel/Makefile +1 -0
index 216890d..c76e6d2 100644
@@ -47,6 +47,7 @@ obj-$(CONFIG_CPU_XSC3)		+= xscale-cp0.o
 obj-$(CONFIG_CPU_MOHAWK)	+= xscale-cp0.o
 obj-$(CONFIG_IWMMXT)		+= iwmmxt.o
 obj-$(CONFIG_CPU_HAS_PMU)	+= pmu.o
+obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
 
 ifneq ($(CONFIG_ARCH_EBSA110),y)
arch/arm/kernel/perf_event.c new file +1347 -0

1,347 lines not on this page · raw message

Signature · 1 line
1.6.5.4
#15 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

In reply to Jean Pihet

Hi Jean,

Quoted 26 lines · Jean Pihet

Agree. Here is the latest version of the detection code, after merging Jamie's latest version:

        unsigned long cpuid = read_cpuid_id() & CPUID_MASK;

        switch (cpuid) {
        case 0xB360:    /* ARM1136 */
        case 0xB560:    /* ARM1156 */
        case 0xB760:    /* ARM1176 */
	    ...
                break;
        case 0xB020:    /* ARM11mpcore */
	    ...
                break;
        case 0xC080:    /* Cortex-A8 */
	    ...
                break;
        case 0xC090:    /* Cortex-A9 */
	    ...
                break;
        default:
                pr_info("no hardware support available\n");
                perf_max_events = -1;
       }
       ...
Quoted 2 lines

Is that OK if we just add 'if (implementor == 0x41) {' before the switch statement, as proposed above?

For the v7 PMU, we can do a bit better than that because the PMU is defined by the architecture. If you read the DIDR[19:16] and it returns either 3 or 4, you have a v7 PMU present so you can make use of the architecturally defined events regardless of the implementer.

So, in response to your question, I reckon you should wrap the switch statement with the implementer check, but add a DIDR check in the else block so that cores with a v7 PMU will at least get support for the standard events.

Cheers,

Will

#16 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Hi Will,

Quoted 37 lines · On Thursday 21 January 2010 13:34:22 Will Deacon wrote:

Hi Jean,

Quoted 26 lines · Jean Pihet

Agree. Here is the latest version of the detection code, after merging Jamie's latest version:

        unsigned long cpuid = read_cpuid_id() & CPUID_MASK;

        switch (cpuid) {
        case 0xB360:    /* ARM1136 */
        case 0xB560:    /* ARM1156 */
        case 0xB760:    /* ARM1176 */
	    ...
                break;
        case 0xB020:    /* ARM11mpcore */
	    ...
                break;
        case 0xC080:    /* Cortex-A8 */
	    ...
                break;
        case 0xC090:    /* Cortex-A9 */
	    ...
                break;
        default:
                pr_info("no hardware support available\n");
                perf_max_events = -1;
       }
       ...
Quoted 2 lines

Is that OK if we just add 'if (implementor == 0x41) {' before the switch statement, as proposed above?

For the v7 PMU, we can do a bit better than that because the PMU is defined by the architecture. If you read the DIDR[19:16] and it returns either 3 or 4, you have a v7 PMU present so you can make use of the architecturally defined events regardless of the implementer.

Quoted 4 lines

So, in response to your question, I reckon you should wrap the switch statement with the implementer check, but add a DIDR check in the else block so that cores with a v7 PMU will at least get support for the standard events.

That makes sense. Are such chipsets already out or planned in the near future? I propose to have the current code working and merged in before supporting the generic v7 cores. Doing so requires to add new set of events mappings.

What do you think?

Quoted 4 lines

Cheers,

Will

Cheers,
Jean

#17 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Hi Jean,

Quoted 5 lines · Jean Pihet
Quoted 4 lines

So, in response to your question, I reckon you should wrap the switch statement with the implementer check, but add a DIDR check in the else block so that cores with a v7 PMU will at least get support for the standard events.

That makes sense. Are such chipsets already out or planned in the near future?

Well, it's basically for supporting any v7 core that isn't designed by ARM. I don't know if any such cores are supported by [mainline] Linux yet, but I'm sure they'll turn up.

Quoted 4 lines

I propose to have the current code working and merged in before supporting the generic v7 cores. Doing so requires to add new set of events mappings.

What do you think?

That makes sense. A8 is probably the most popular v7 core at the moment, so supporting that should be the priority.

Cheers,

Will

#18 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

In reply to Will Deacon
Quoted 4 lines · Will Deacon

For the v7 PMU, we can do a bit better than that because the PMU is defined by the architecture. If you read the DIDR[19:16] and it returns either 3 or 4, you have a v7 PMU present so you can make use of the architecturally defined events regardless of the implementer.

However, you can't just check DIDR - DIDR doesn't exist unless you have the new ID scheme - and you can tell that by:

if MIDR[31:28] != 0x41 || (MIDR[12:15] != 0 && MIDR[12:15] != 7)

	newid = MIDR[19:16] == 15

else
newid = 0

or currently check for cpu_architecture() >= CPU_ARCH_ARMv6 && MIDR[19:16] == 15 (the additional qualification is needed because ARMv6 CPUs can have either the old or new schemes.)

However, what also needs checking is how DIDR is specified for ARMv6, and whether that clashes with the ARMv7 version - as I mentioned before, the new ID scheme is not without its own set of weird changes as well.

#19 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

In reply to Jean Pihet

Where do I find a repository that contains the latest performance events/ARM efforts?

Quoted 97 lines

-----Original Message-----
From: linux-arm-kernel-bounces at lists.infradead.org [mailto:linux-arm- kernel-bounces at lists.infradead.org] On Behalf Of Jean Pihet
Sent: Thursday, January 21, 2010 1:22 PM
To: Russell King - ARM Linux
Cc: 'Jamie Iles'; Will Deacon; linux-arm-kernel at lists.infradead.org
Subject: Re: [PATCH 5/5] arm/perfevents: implement perf event support for ARMv6

Quoted 5 lines · On Thursday 21 January 2010 11:38:03 Russell King - ARM Linux wrote:
Quoted 4 lines · Will Deacon

Hi Jamie,

Quoted 1 line · Jamie Iles

Given the difficulty in determining the CPU type 100%, this

should be

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

changed to:

	unsigned long cpuid = read_cpuid_id();
	unsigned long implementor = (cpuid & 0xFF000000) >> 24;
	unsigned long part_number = (cpuid & 0xFFF0);

	/* We only support ARM CPUs implemented by ARM at the

moment. */

Quoted 7 lines
Quoted 7 lines
Quoted 5 lines
	if (implementor == 0x41) {
		switch (part_number) {
		case 0xB360:
		case 0xB560:
			etc

Whilst I understand that the whole cpuid thing is a complete mess

[I saw

Quoted 1 line
Quoted 1 line

the lkml posts yesterday], I'm not sure this is necessary for v7

cores.

Quoted 1 line
Quoted 1 line

For v7, the PMU is part of the architecture and so *must* be

implemented

Quoted 11 lines
Quoted 2 lines

in the way described in the ARM ARM [Chapter 9], regardless of the implementer.

This function is called whenever the PMU support is built in - and this is the first place a decision is made about how to handle stuff.

Merely checking the part number without checking the implementer is nonsense - the part number is defined by the implmenter, not ARM, so the part number can only be interpreted with knowledge of the implementer.

Quoted 4 lines

So, when v7 gets added, checking the main ID register is the wrong thing to do.

Given that cpu_architecture() appears to have been redefined to

return

Quoted 2 lines

the MMU architecture, we have no real way to properly determine if we have a v7 PMU present - in fact, the whole "are we v6 or v7 or

something

Quoted 4 lines

later" question seems to be extremely muddy and indeterminant.

So I don't think even checking cpu_architecture() == CPU_ARCH_ARMv7 is the right thing either.

Agree. Here is the latest version of the detection code, after merging Jamie's
latest version:

        unsigned long cpuid = read_cpuid_id() & CPUID_MASK;

        switch (cpuid) {
        case 0xB360:    /* ARM1136 */
        case 0xB560:    /* ARM1156 */
        case 0xB760:    /* ARM1176 */
	    ...
                break;
        case 0xB020:    /* ARM11mpcore */
	    ...
                break;
        case 0xC080:    /* Cortex-A8 */
	    ...
                break;
        case 0xC090:    /* Cortex-A9 */
	    ...
                break;
        default:
                pr_info("no hardware support available\n");
                perf_max_events = -1;
       }
       ...

Is that OK if we just add 'if (implementor == 0x41) {' before the switch
statement, as proposed above?

Jean

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#20 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Quoted 2 lines · Tomasz Fujak

Where do I find a repository that contains the latest performance events/ARM efforts?

I've just submitted the generic/ARMv6 stuff to the patch system. Hopefully this will end up in Russell's tree soon.

Jamie

#21 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Hi,

Quoted 6 lines · On Tuesday 26 January 2010 17:09:29 Jamie Iles wrote:
Quoted 2 lines · Tomasz Fujak

Where do I find a repository that contains the latest performance events/ARM efforts?

I've just submitted the generic/ARMv6 stuff to the patch system. Hopefully this will end up in Russell's tree soon.

I am about to submit the patch for ARMv7, so hopefully it will end up in Russell's tree soon as well.

Quoted 2 lines

Jamie

Jean

#22 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Hi,

Here is the latest version of the patch, after review on the ML.

Adds the Performance Events support for ARMv7 processor, using the PMNC unit in HW.

Supports the following:
- Cortex-A8 and Cortex-A9 processors,
- dynamic detection of the number of available counters, based on the PMCR value,
- runtime detection of the CPU arch (v6 or v7) and model (Cortex-A8 or Cortex-A9)

Tested on OMAP3 (Cortex-A8) only.

Regards,
Jean

Quoted 10 lines · On Tuesday 26 January 2010 17:11:44 Jean Pihet wrote:

Hi,

Quoted 6 lines · On Tuesday 26 January 2010 17:09:29 Jamie Iles wrote:
Quoted 2 lines · Tomasz Fujak

Where do I find a repository that contains the latest performance events/ARM efforts?

I've just submitted the generic/ARMv6 stuff to the patch system. Hopefully this will end up in Russell's tree soon.

Quoted 6 lines

I am about to submit the patch for ARMv7, so hopefully it will end up in Russell's tree soon as well.

Quoted 1 line

Jamie

Jean

---

Quoted 1 line

From 6e8e6e710c93eb16885c5c789f689a86d824bdba Mon Sep 17 00:00:00 2001

From: Jean Pihet <[email protected]>
Date: Fri, 18 Dec 2009 17:46:21 +0100
Subject: [PATCH] arm/perfevents: add support for ARMv7

Adds the Performance Events support for ARMv7 processor, using the PMNC unit in HW.

Supports the following:
- Cortex-A8 and Cortex-A9 processors,
- dynamic detection of the number of available counters, based on the PMCR value,
- runtime detection of the CPU arch (v6 or v7) and model (Cortex-A8 or Cortex-A9)

Tested on OMAP3 (Cortex-A8) only.

---
 arch/arm/Kconfig             |    2 +-
 arch/arm/kernel/perf_event.c |  934 
+++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 931 insertions(+), 5 deletions(-)
arch/arm/Kconfig +1 -1
index 6cbcba7..bc177cd 100644
@@ -1181,7 +1181,7 @@ config HIGHPTE
 
 config HW_PERF_EVENTS
 	bool "Enable hardware performance counter support for perf events"
-	depends on PERF_EVENTS && CPU_HAS_PMU && CPU_V6
+	depends on PERF_EVENTS && CPU_HAS_PMU && (CPU_V6 || CPU_V7)
 	default y
 	help
 	  Enable hardware performance counter support for perf events. If
arch/arm/kernel/perf_event.c +930 -4

971 lines not on this page · raw message

Signature · 1 line
1.6.2.5.168.g3823
#23 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Hi Jean,

Quoted 3 lines · Jean Pihet

Here is the latest version of the patch, after review on the ML. Adds the Performance Events support for ARMv7 processor, using the PMNC unit in HW.

I tested this on a dual-core Cortex-A9 [Realview PBX board]. One thing I noticed was that, even if you don't add the PMU IRQs to kernel/pmu.c, perf will still report event counts [I guess this is due to sampling on context switch etc]. However, if the IRQs are defined, but for some reason we fail to request them, then the armpmu_reserve_hardware function will fail. Actually, the return value appears to be uninitialised if you don't have any IRQs defined.

Anyway, apart from that, it appeared to work fine.

Will

#24 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Hi Will,

Quoted 11 lines · On Wednesday 27 January 2010 18:26:27 Will Deacon wrote:

Hi Jean,

Quoted 3 lines · Jean Pihet

Here is the latest version of the patch, after review on the ML. Adds the Performance Events support for ARMv7 processor, using the PMNC unit in HW.

I tested this on a dual-core Cortex-A9 [Realview PBX board]. One thing I noticed was that, even if you don't add the PMU IRQs to kernel/pmu.c, perf will still report event counts [I guess this is due to sampling on context switch etc].

Yes, Perf Events uses the timer interrupts and the scheduler to control the events to be traced. The result is a really low IRQ count, which is good on the Cortex-A8 PMUs units that have the HW problem (known as errata).

Quoted 3 lines

However, if the IRQs are
defined, but for some reason we fail to request them, then the armpmu_reserve_hardware function will fail.

That is the expected behaviour, isn't it?
Why is the PMU request failing? That is worth investigating. I never had that problem on the Cortex-A8. Is it caused because of the multicore?

Quoted 2 lines

Actually, the return
value appears to be uninitialised if you don't have any IRQs defined.

If the PMU request fails the IRQ should not be requested, so I think it is ok. Is that correct?

Quoted 2 lines

Anyway, apart from that, it appeared to work fine.

Good!

Thanks for testing!
Jean

Quoted 3 lines

Will

#25 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Hi Jean,

Quoted 6 lines · Jean Pihet
Quoted 3 lines

However, if the IRQs are
defined, but for some reason we fail to request them, then the armpmu_reserve_hardware function will fail.

That is the expected behaviour, isn't it?
Why is the PMU request failing? That is worth investigating. I never had that problem on the Cortex-A8. Is it caused because of the multicore?

Don't worry, requesting the IRQs did not fail. I was simply speculating about the behaviour if it *does* fail. Then armpmu_reserve_hardware will return an error, which will prevent the event being added. Instead, we could print a warning, but continue without IRQs in the same manner as though they had not been defined in pmu.c.

Quoted 4 lines
Quoted 2 lines

Actually, the return
value appears to be uninitialised if you don't have any IRQs defined.

If the PMU request fails the IRQ should not be requested, so I think it is ok. Is that correct?

What I mean is, if pmu_irqs->num_irqs < 1, then we return err without ever setting it. In fact, we might even end up freeing IRQs which we haven't requested which could cause all sorts of problems.

Quoted 8 lines
Quoted 2 lines

Anyway, apart from that, it appeared to work fine.

Good!

Thanks for testing!
Jean

Quoted 1 line

That's alright, but it's conditional on sorting out the above! :)

Cheers,

Will

#26 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Quoted 11 lines · Will Deacon

Hi Jean,

Quoted 6 lines · Jean Pihet
Quoted 3 lines

However, if the IRQs are
defined, but for some reason we fail to request them, then the armpmu_reserve_hardware function will fail.

That is the expected behaviour, isn't it?
Why is the PMU request failing? That is worth investigating. I never had that problem on the Cortex-A8. Is it caused because of the multicore?

Quoted 5 lines

Don't worry, requesting the IRQs did not fail. I was simply speculating about the behaviour if it *does* fail. Then armpmu_reserve_hardware will return an error, which will prevent the event being added. Instead, we could print a warning, but continue without IRQs in the same manner as though they had not been defined in pmu.c.

This was my mistake and I don't think we should continue - we'd _probably_ be ok for sampling counters, but for the counting counters we could hit problems if the counters weren't being scheduled in and out. For example if someone did 'perf stat -a -e cycles -- sleep 1m' then the cycle counter would not need to be scheduled out, the counter could wrap a few times and we wouldn't know because we didn't get an interrupt.

I'd suggest the following patch to fix it.

arch/arm/kernel/perf_event.c +1 -0
index 36a23cc..7b1022b 100644
@@ -320,6 +320,7 @@ armpmu_reserve_hardware(void)
 
 	if (pmu_irqs->num_irqs < 1) {
 		pr_err("no irqs for PMUs defined\n");
+		return -ENODEV;
 	}
 
 	for (i = 0; i < pmu_irqs->num_irqs; ++i) {
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Actually, the return
value appears to be uninitialised if you don't have any IRQs defined.

If the PMU request fails the IRQ should not be requested, so I think it is ok. Is that correct?

What I mean is, if pmu_irqs->num_irqs < 1, then we return err without ever setting it. In fact, we might even end up freeing IRQs which we haven't requested which could cause all sorts of problems.

Good spot! I'm suprised gcc didn't pick this one up. The patch above should prvent this.

Russell, shall I supersede the old patch in the patch system and roll in the patch above?

Jamie

#27 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Quoted 2 lines · Jamie Iles

Russell, shall I supersede the old patch in the patch system and roll in the patch above?

If it's broken, yes please.

#28 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

In reply to Jamie Iles
Quoted 6 lines · Jamie Iles

This was my mistake and I don't think we should continue - we'd _probably_ be ok for sampling counters, but for the counting counters we could hit problems if the counters weren't being scheduled in and out. For example if someone did 'perf stat -a -e cycles -- sleep 1m' then the cycle counter would not need to be scheduled out, the counter could wrap a few times and we wouldn't know because we didn't get an interrupt.

Jamie,

Please let me know when these patches have stabilised.

#29 lore raw

PATCH 5/5 arm/perfevents: implement perf event support for ARMv6

Quoted 11 lines · Russell King - ARM Linux
Quoted 6 lines · Jamie Iles

This was my mistake and I don't think we should continue - we'd _probably_ be ok for sampling counters, but for the counting counters we could hit problems if the counters weren't being scheduled in and out. For example if someone did 'perf stat -a -e cycles -- sleep 1m' then the cycle counter would not need to be scheduled out, the counter could wrap a few times and we wouldn't know because we didn't get an interrupt.

Jamie,

Please let me know when these patches have stabilised.

I think they're good to go now. I sent the original patch as the update by accident as 5902/2 but 5902/3 includes the fix.

Jamie

#30 lore raw

PATCH 4/5 arm: enable support for software perf events

In reply to Jamie Iles
Quoted 19 lines · Jamie Iles

The perf events subsystem allows counting of both hardware and software events. This patch implements the bare minimum for software performance events.

Cc Peter Zijlstra <[email protected]>
Cc Ingo Molnar <[email protected]>
---
 arch/arm/Kconfig                  |    2 ++
 arch/arm/include/asm/perf_event.h |   31 +++++++++++++++++++++++++++++++
 arch/arm/mm/fault.c               |    7 +++++++
 3 files changed, 40 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/perf_event.h
arch/arm/Kconfig +0 -0
index 293a879..72646b2 100644

arch/arm/Kconfig config ARM · line 23

Quoted 3 lines
arch/arm/Kconfig +0 -0
@@ -21,6 +21,8 @@ config ARM
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZO
 	select GENERIC_ATOMIC64

This conflicts - this select is only if !CPU_32v6K in my kernel.

What's the implication? Does this perf stuff require these atomic64 stuff (in which case, those symbols should only be selected if GENERIC_ATOMIC64 is also selected.)

Please sort this out.

#31 lore raw

PATCH 4/5 arm: enable support for software perf events

Hi Russell, Jamie,

Quoted 12 lines · Russell King

arch/arm/Kconfig config ARM · line 23

Quoted 9 lines
arch/arm/Kconfig +0 -0
index 293a879..72646b2 100644
@@ -21,6 +21,8 @@ config ARM
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZO
 	select GENERIC_ATOMIC64

This conflicts - this select is only if !CPU_32v6K in my kernel.

Quoted 3 lines

What's the implication? Does this perf stuff require these atomic64 stuff (in which case, those symbols should only be selected if GENERIC_ATOMIC64 is also selected.)

This conflicts because I submitted native atomic64 routines recently. The native routines can only be used if CPU_32v6K is asserted, falling back on the generic implementation otherwise.

Jamie has based his patches on a tree without the native routines, so to resolve this the GENERIC_ATOMIC64 if !CPU_32v6K should be left alone [then perf will use whatever it is given].

Cheers,

Will

author
#32 lore raw

PATCH 4/5 arm: enable support for software perf events

In reply to Russell King - ARM Linux
Quoted 26 lines · Russell King - ARM Linux
Quoted 19 lines · Jamie Iles

The perf events subsystem allows counting of both hardware and software events. This patch implements the bare minimum for software performance events.

Cc Peter Zijlstra <[email protected]>
Cc Ingo Molnar <[email protected]>
---
 arch/arm/Kconfig                  |    2 ++
 arch/arm/include/asm/perf_event.h |   31 +++++++++++++++++++++++++++++++
 arch/arm/mm/fault.c               |    7 +++++++
 3 files changed, 40 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/perf_event.h
arch/arm/Kconfig +0 -0
index 293a879..72646b2 100644

arch/arm/Kconfig config ARM · line 23

Quoted 3 lines
arch/arm/Kconfig +0 -0
@@ -21,6 +21,8 @@ config ARM
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZO
 	select GENERIC_ATOMIC64

This conflicts - this select is only if !CPU_32v6K in my kernel.

Quoted 5 lines

What's the implication? Does this perf stuff require these atomic64 stuff (in which case, those symbols should only be selected if GENERIC_ATOMIC64 is also selected.)

Please sort this out.

As Will mentioned, the correct case should be 'GENERIC_ATOMIC64 if (!CPU_32v6K)' due to my patches being off a tree without the native atomic64's. I can rebase onto next if that's easier.

Jamie

#33 lore raw

PATCH 4/5 arm: enable support for software perf events

Quoted 27 lines · Jamie Iles
Quoted 26 lines · Russell King - ARM Linux
Quoted 19 lines · Jamie Iles

The perf events subsystem allows counting of both hardware and software events. This patch implements the bare minimum for software performance events.

Cc Peter Zijlstra <[email protected]>
Cc Ingo Molnar <[email protected]>
---
 arch/arm/Kconfig                  |    2 ++
 arch/arm/include/asm/perf_event.h |   31 +++++++++++++++++++++++++++++++
 arch/arm/mm/fault.c               |    7 +++++++
 3 files changed, 40 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/perf_event.h
arch/arm/Kconfig +0 -0
index 293a879..72646b2 100644

arch/arm/Kconfig config ARM · line 23

Quoted 3 lines
arch/arm/Kconfig +0 -0
@@ -21,6 +21,8 @@ config ARM
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZO
 	select GENERIC_ATOMIC64

This conflicts - this select is only if !CPU_32v6K in my kernel.

Quoted 8 lines
Quoted 5 lines

What's the implication? Does this perf stuff require these atomic64 stuff (in which case, those symbols should only be selected if GENERIC_ATOMIC64 is also selected.)

Please sort this out.

As Will mentioned, the correct case should be 'GENERIC_ATOMIC64 if (!CPU_32v6K)' due to my patches being off a tree without the native atomic64's. I can rebase onto next if that's easier.

Much prefer having them rebased onto 7558b1f, which is in -next if you can manage that.

The better solution (which I think I'll do just before the merge window) is to re-order the 'select' statements to be alphabetic, which should help separate some of these conflicts.

#34 lore raw

PATCH 4/5 arm: enable support for software perf events

Quoted 32 lines · Russell King - ARM Linux
Quoted 31 lines · Jamie Iles
Quoted 30 lines · Russell King - ARM Linux
Quoted 19 lines · Jamie Iles

The perf events subsystem allows counting of both hardware and software events. This patch implements the bare minimum for software performance events.

Cc Peter Zijlstra <[email protected]>
Cc Ingo Molnar <[email protected]>
---
 arch/arm/Kconfig                  |    2 ++
 arch/arm/include/asm/perf_event.h |   31 +++++++++++++++++++++++++++++++
 arch/arm/mm/fault.c               |    7 +++++++
 3 files changed, 40 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/perf_event.h
arch/arm/Kconfig +0 -0
index 293a879..72646b2 100644

arch/arm/Kconfig config ARM · line 23

Quoted 3 lines
arch/arm/Kconfig +0 -0
@@ -21,6 +21,8 @@ config ARM
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZO
 	select GENERIC_ATOMIC64

This conflicts - this select is only if !CPU_32v6K in my kernel.

What's the implication? Does this perf stuff require these atomic64 stuff (in which case, those symbols should only be selected if GENERIC_ATOMIC64 is also selected.)

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

Please sort this out.

As Will mentioned, the correct case should be 'GENERIC_ATOMIC64 if (!CPU_32v6K)' due to my patches being off a tree without the native atomic64's. I can rebase onto next if that's easier.

Much prefer having them rebased onto 7558b1f, which is in -next if you can manage that.

Done - I've rebased the complete series.

Thanks,

Jamie

#35 lore raw

PATCH 2/5 arm/oprofile: reserve the PMU when starting

In reply to Jamie Iles

Hi,

Quoted 6 lines · Jamie Iles

Make sure that we have access to the performance counters and that they aren't being used by perf events or anything else.

Cc Will Deacon <[email protected]>
Cc Jean Pihet <[email protected]>
Quoted 9 lines
---
 arch/arm/oprofile/op_model_arm11_core.c |    4 +-
 arch/arm/oprofile/op_model_arm11_core.h |    4 +-
 arch/arm/oprofile/op_model_mpcore.c     |   42 ++++++++++++++++--------------
 arch/arm/oprofile/op_model_v6.c         |   30 ++++++++++++++--------
 arch/arm/oprofile/op_model_v7.c         |   30 ++++++++++++++--------
 arch/arm/oprofile/op_model_v7.h         |    4 +-
 arch/arm/oprofile/op_model_xscale.c     |   35 ++++++++++++++-----------
 7 files changed, 85 insertions(+), 64 deletions(-)

// CUT

Quoted 59 lines
arch/arm/oprofile/op_model_mpcore.c +12 -10
index 4ce0f98..f73ce87 100644
@@ -32,6 +32,7 @@
 /* #define DEBUG */
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/sched.h>
 #include <linux/oprofile.h>
 #include <linux/interrupt.h>
@@ -43,6 +44,7 @@
 #include <mach/hardware.h>
 #include <mach/board-eb.h>
 #include <asm/system.h>
+#include <asm/pmu.h>
 
 #include "op_counter.h"
 #include "op_arm_model.h"
@@ -58,6 +60,7 @@
  * Bitmask of used SCU counters
  */
 static unsigned int scu_em_used;
+static const struct pmu_irqs *pmu_irqs;
 
 /*
  * 2 helper fns take a counter number from 0-7 (not the userspace-visible counter number)
@@ -225,33 +228,40 @@ static int em_setup_ctrs(void)
 	return 0;
 }
 
-static int arm11_irqs[] = {
-	[0]	= IRQ_EB11MP_PMU_CPU0,
-	[1]	= IRQ_EB11MP_PMU_CPU1,
-	[2]	= IRQ_EB11MP_PMU_CPU2,
-	[3]	= IRQ_EB11MP_PMU_CPU3
-};
-
 static int em_start(void)
 {
 	int ret;
 
-	ret = arm11_request_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs));
+	pmu_irqs = reserve_pmu();
+	if (IS_ERR(pmu_irqs)) {
+		ret = PTR_ERR(pmu_irqs);
+		goto out;
+	}
+
+	ret = arm11_request_interrupts(pmu_irqs->irqs, pmu_irqs->num_irqs);
 	if (ret == 0) {
 		em_call_function(arm11_start_pmu);
 
 		ret = scu_start();
-		if (ret)
-			arm11_release_interrupts(arm11_irqs, ARRAY_SIZE(arm11_irqs));
+		if (ret) {
+			arm11_release_interrupts(pmu_irqs->irqs,

arch/arm/oprofile/op_model_mpcore.c static int em_setup_ctrs(void) · line 257

Quoted 10 lines
arch/arm/oprofile/op_model_mpcore.c +7 -0
+						 pmu_irqs->num_irqs);
+		} else {
+			release_pmu(pmu_irqs);
+			pmu_irqs = NULL;
+		}
 	}
+
+out:
 	return ret;
 }

The "} else {" clause above broke OProfile on ARM11 MPCore. Here's a trivial fix tested on ARM Ltd. RealView EB ARM11 MPCore:

#36 lore raw

PATCH 2/5 arm/oprofile: reserve the PMU when starting

Quoted 22 lines · George G. Davis

From 18018f4e439ebcf9358790887502764b18459c9c Mon Sep 17 00:00:00 2001
From: George G. Davis <[email protected]>
Date: Fri, 5 Feb 2010 00:38:01 -0500
Subject: [PATCH] ARM: Fix ARM11 MPCore OProfile breakage due to ARM patch 5901/2

The recent "fe6c67f ARM: 5901/2: arm/oprofile: reserve the PMU when starting" commit broke OProfile support on ARM11 MPCore targets by adding a misplaced "} else {" clause in function em_start() which results in a call to release_pmu() even though the PMU is in use which in turn results in an oops while using OProfile. Removing the stray else clause fixes the problem.

---
 arch/arm/oprofile/op_model_mpcore.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)
arch/arm/oprofile/op_model_mpcore.c +0 -0
index f73ce87..0d4f099 100644

arch/arm/oprofile/op_model_mpcore.c static int em_start(void)

Quoted 10 lines
arch/arm/oprofile/op_model_mpcore.c +0 -2
@@ -246,7 +246,6 @@ static int em_start(void)
 		if (ret) {
 			arm11_release_interrupts(pmu_irqs->irqs,
 						 pmu_irqs->num_irqs);
-		} else {
 			release_pmu(pmu_irqs);
 			pmu_irqs = NULL;
 		}
 
 
--

Hi George,

Good catch. Looks good to me.

Jamie

#37 lore raw

PATCH 1/5 arm: provide a mechanism to reserve performance counters

In reply to Jamie Iles
Quoted 3 lines · Jamie Iles

To add support for perf events and to allow the hardware counters to be shared with oprofile, we need a way to reserve access to the pmu (performance monitor unit).

[snip]

Quoted 28 lines
arch/arm/kernel/pmu.c new file +22 -0
new file mode 100644
index 0000000..688d450
@@ -0,0 +1,105 @@
+/*
+ *  linux/arch/arm/kernel/pmu.c
+ *
+ *  Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/cpumask.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/pmu.h>
+
+/*
+ * Define the IRQs for the system. We could use something like a platform
+ * device but that seems fairly heavyweight for this. Also, the performance

arch/arm/kernel/pmu.c line 32

Quoted 10 lines
arch/arm/kernel/pmu.c new file +10 -0
+ * counters can't be removed or hotplugged.
+ *
+ * Ordering is important: init_pmu() will use the ordering to set the affinity
+ * to the corresponding core. e.g. the first interrupt will go to cpu 0, the
+ * second goes to cpu 1 etc.
+ */
+static const int irqs[] = {
+#ifdef CONFIG_ARCH_PC3XX
+	IRQ_NPMUIRQ,
+#elif defined(CONFIG_ARCH_OMAP2)

This one (ARCH_PC3XX) shouldn't have made it in here as the platform isn't in mainline. I'll remove this before submitting the patch.

Jamie