ARM perf events support v5
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(-)
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
@@ -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
@@ -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
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.
--- 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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
@@ -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
@@ -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
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.
--- 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
@@ -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
@@ -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
@@ -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
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'.
--- 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
@@ -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
@@ -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
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_EVENTSand define the interrupts for the counters inarch/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:
etcJamie
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
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: etcWhilst 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
PATCH 5/5 arm/perfevents: implement perf event support for ARMv6
In reply to Jamie IlesQuoted 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.
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_ARMv7is the right thing either.
Indeed. That always catches me out!
Cheers,
Will
PATCH 5/5 arm/perfevents: implement perf event support for ARMv6
In reply to Russell King - ARM LinuxQuoted 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: etcQuoted 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_ARMv7is 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
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: etcQuoted 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_ARMv7is 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
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: etcQuoted 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_ARMv7is 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
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'.
--- 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
@@ -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
@@ -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
PATCH 5/5 arm/perfevents: implement perf event support for ARMv6
In reply to Jean PihetHi 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
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
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
PATCH 5/5 arm/perfevents: implement perf event support for ARMv6
In reply to Will DeaconQuoted 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.
PATCH 5/5 arm/perfevents: implement perf event support for ARMv6
In reply to Jean PihetWhere 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 ARMv6Quoted 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 themoment. */
Quoted 7 lines
Quoted 7 lines
Quoted 5 lines
if (implementor == 0x41) { switch (part_number) { case 0xB360: case 0xB560: etcWhilst 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 toreturn
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_ARMv7is 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
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
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
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
6e8e6e710c93eb16885c5c789f689a86d824bdbaMon 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
@@ -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
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
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 thearmpmu_reserve_hardwarefunction 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
Tested-by Will Deacon <[email protected]>Will
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 thearmpmu_reserve_hardwarefunction 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!
JeanQuoted 1 line
Tested-by Will Deacon <[email protected]>
That's alright, but it's conditional on sorting out the above! :)
Cheers,
Will
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 thearmpmu_reserve_hardwarefunction 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_hardwarewill 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 inpmu.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
@@ -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
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.
PATCH 5/5 arm/perfevents: implement perf event support for ARMv6
In reply to Jamie IlesQuoted 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.
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
PATCH 4/5 arm: enable support for software perf events
In reply to Jamie IlesQuoted 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.
Signed-off-by Jamie Iles <[email protected]>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.harch/arm/Kconfig +0
-0
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.
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@@ -21,6 +21,8 @@ config ARM select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZO select GENERIC_ATOMIC64This 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_ATOMIC64is 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
PATCH 4/5 arm: enable support for software perf events
In reply to Russell King - ARM LinuxQuoted 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.
Signed-off-by Jamie Iles <[email protected]>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.harch/arm/Kconfig +0
-0arch/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_ATOMIC64This 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_ATOMIC64is 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
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.
Signed-off-by Jamie Iles <[email protected]>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.harch/arm/Kconfig +0
-0arch/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_ATOMIC64This 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_ATOMIC64is also selected.)Please sort this out.
As Will mentioned, the correct case should be '
GENERIC_ATOMIC64if (!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.
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.
Signed-off-by Jamie Iles <[email protected]>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.harch/arm/Kconfig +0
-0arch/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_ATOMIC64This 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_ATOMIC64is also selected.)
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
Please sort this out.
As Will mentioned, the correct case should be '
GENERIC_ATOMIC64if (!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
PATCH 2/5 arm/oprofile: reserve the PMU when starting
In reply to Jamie IlesHi,
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]>Signed-off-by Jamie Iles <[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@@ -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:
PATCH 2/5 arm/oprofile: reserve the PMU when starting
Quoted 22 lines · George G. Davis
From
18018f4e439ebcf9358790887502764b18459c9cMon 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/2The 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 torelease_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.Signed-off-by George G. Davis <[email protected]>--- arch/arm/oprofile/op_model_mpcore.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-)arch/arm/oprofile/op_model_mpcore.c +0
-0
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
PATCH 1/5 arm: provide a mechanism to reserve performance counters
In reply to Jamie IlesQuoted 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@@ -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