Skip to contentSkip to conversation

Support hardware perf counters on xtensa

PATCH Superseded Max Filippov 4 participants 20 messages Jul 6, 2015 – Jul 7, 2015

Subsystems (2)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

Max Filippov

author maintainer
#0 lore raw

cover Support hardware perf counters on xtensa

Hello,

this series adds support for hardware performance counters in counting and sampling modes as well as for page fault counting. It reorganizes stack stracing code to share it between old oprofile and new perf interfaces, and improves kernel stack traces both for builtin debug functions and for gdb.

Max Filippov (8):
xtensa: clean up Kconfig dependencies for custom cores
xtensa: keep exception/interrupt stack continuous
xtensa: move oprofile stack tracing to stacktrace.c
xtensa: select PERF_USE_VMALLOC for cache-aliasing configurations
xtensa: add profiling IRQ type to xtensa_irq_map
xtensa: count software page fault perf events
xtensa: implement counting and sampling perf events perf tools: xtensa: add DWARF register names

 arch/xtensa/Kconfig                      |  22 +-
 arch/xtensa/include/asm/stacktrace.h     |   8 +
 arch/xtensa/kernel/Makefile              |   1 +
 arch/xtensa/kernel/entry.S               |  60 +++--
 arch/xtensa/kernel/irq.c                 |   6 +
 arch/xtensa/kernel/perf_event.c          | 450 +++++++++++++++++++++++++++++++
 arch/xtensa/kernel/stacktrace.c          | 167 +++++++++++-
 arch/xtensa/mm/fault.c                   |   7 +
 arch/xtensa/oprofile/backtrace.c         | 158 +----------
 tools/perf/arch/xtensa/Build             |   1 +
 tools/perf/arch/xtensa/Makefile          |   3 +
 tools/perf/arch/xtensa/util/Build        |   1 +
 tools/perf/arch/xtensa/util/dwarf-regs.c |  25 ++
 13 files changed, 725 insertions(+), 184 deletions(-)
 create mode 100644 arch/xtensa/kernel/perf_event.c
 create mode 100644 tools/perf/arch/xtensa/Build
 create mode 100644 tools/perf/arch/xtensa/Makefile
 create mode 100644 tools/perf/arch/xtensa/util/Build
 create mode 100644 tools/perf/arch/xtensa/util/dwarf-regs.c
Signature · 1 line
1.8.1.4
author maintainer
#1 lore raw

PATCH 1/8 xtensa: clean up Kconfig dependencies for custom cores

---
 arch/xtensa/Kconfig | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)
arch/xtensa/Kconfig +3 -8
index 87be10e..ba22699 100644
@@ -61,9 +61,7 @@ config TRACE_IRQFLAGS_SUPPORT
 	def_bool y
 
 config MMU
-	bool
-	default n if !XTENSA_VARIANT_CUSTOM
-	default XTENSA_VARIANT_MMU if XTENSA_VARIANT_CUSTOM
+	def_bool n
 
 config VARIANT_IRQ_SWITCH
 	def_bool n
@@ -71,9 +69,6 @@ config VARIANT_IRQ_SWITCH
 config HAVE_XTENSA_GPIO32
 	def_bool n
 
-config MAY_HAVE_SMP
-	def_bool n
-
 menu "Processor type and features"
 
 choice
@@ -100,7 +95,6 @@ config XTENSA_VARIANT_DC233C
 
 config XTENSA_VARIANT_CUSTOM
 	bool "Custom Xtensa processor configuration"
-	select MAY_HAVE_SMP
 	select HAVE_XTENSA_GPIO32
 	help
 	  Select this variant to use a custom Xtensa processor configuration.
@@ -126,6 +120,7 @@ config XTENSA_VARIANT_MMU
 	bool "Core variant has a Full MMU (TLB, Pages, Protection, etc)"
 	depends on XTENSA_VARIANT_CUSTOM
 	default y
+	select MMU
 	help
 	  Build a Conventional Kernel with full MMU support,
 	  ie: it supports a TLB with auto-loading, page protection.
@@ -143,7 +138,7 @@ source "kernel/Kconfig.preempt"
 
 config HAVE_SMP
 	bool "System Supports SMP (MX)"
-	depends on MAY_HAVE_SMP
+	depends on XTENSA_VARIANT_CUSTOM
 	select XTENSA_MX
 	help
 	  This option is use to indicate that the system-on-a-chip (SOC)
Signature · 1 line
1.8.1.4
#2 lore raw

Re: [PATCH 1/8] xtensa: clean up Kconfig dependencies for custom cores

arch/xtensa/Kconfig config TRACE_IRQFLAGS_SUPPORT · line 64

Quoted 8 lines · Max Filippov
arch/xtensa/Kconfig +1 -3
 
 config MMU
-	bool
-	default n if !XTENSA_VARIANT_CUSTOM
-	default XTENSA_VARIANT_MMU if XTENSA_VARIANT_CUSTOM
+	def_bool n

Doesn't
config MMU
bool

(ie, drop the 'n' default) work just as well?

Paul Bolle

author maintainer
#3 lore raw

PATCH 2/8 xtensa: keep exception/interrupt stack continuous

In reply to Max Filippov

Restore original a0 in the kernel exception stack frame. This way it looks like the frame that got interrupt/exception did alloca (copy a0 and a1 potentially spilled under old stack to the new location as well) to save registers and then did a call to handler. The point where interrupt/exception was taken is not in the stack chain, only in pt_regs (call4 from that address can be simulated to keep it in the stack trace).

---
 arch/xtensa/kernel/entry.S | 60 +++++++++++++++++++++++++++-------------------
 1 file changed, 35 insertions(+), 25 deletions(-)
arch/xtensa/kernel/entry.S +35 -25
index 82bbfa5..ab6a857 100644
@@ -218,7 +218,7 @@ _user_exception:
 	/* We are back to the original stack pointer (a1) */
 
 2:	/* Now, jump to the common exception handler. */
-
+	movi	a0, 0			# terminate user stack trace with 0
 	j	common_exception
 
 ENDPROC(user_exception)
@@ -264,6 +264,19 @@ ENTRY(kernel_exception)
 	.globl _kernel_exception
 _kernel_exception:
 
+	/* Copy spill slots of a0 and a1 to imitate movsp
+	 * in order to keep exception stack continuous
+	 */
+	l32i	a0, a1, PT_AREG1
+	addi	a2, a1, -16
+	addi	a0, a0, -16
+	l32i	a3, a0, 0
+	l32i	a0, a0, 4
+	s32i	a3, a2, 0
+	s32i	a0, a2, 4
+
+	l32i	a0, a1, PT_AREG0	# restore saved a0
+
 	/* Save SAR and turn off single stepping */
 
 	movi	a2, 0
@@ -338,52 +351,50 @@ common_exception:
 	xsr	a2, lcount
 	s32i	a2, a1, PT_LCOUNT
 
-	/* It is now save to restore the EXC_TABLE_FIXUP variable. */
+	/* It is now safe to restore the EXC_TABLE_FIXUP variable. */
 
-	rsr	a0, exccause
 	movi	a3, 0
 	rsr	a2, excsave1
-	s32i	a0, a1, PT_EXCCAUSE
 	s32i	a3, a2, EXC_TABLE_FIXUP
 
-	/* All unrecoverable states are saved on stack, now, and a1 is valid,
-	 * so we can allow exceptions and interrupts (*) again.
-	 * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
+	/* Save remaining unrecoverable states (exccause, ps) on stack.
+	 * Now we can allow exceptions again. In case we've got an interrupt
+	 * PS.INTLEVEL is set to LOCKLEVEL disabling furhter interrupts,
+	 * otherwise it's left unchanged.
 	 *
-	 * (*) We only allow interrupts if they were previously enabled and
-	 *     we're not handling an IRQ
+	 * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
 	 */
 
 	rsr	a3, ps
-	addi	a0, a0, -EXCCAUSE_LEVEL1_INTERRUPT
-	movi	a2, LOCKLEVEL
+	movi	a2, (1 << PS_WOE_BIT)
 	extui	a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH
-					# a3 = PS.INTLEVEL
-	moveqz	a3, a2, a0		# a3 = LOCKLEVEL iff interrupt
-	movi	a2, 1 << PS_WOE_BIT
 	or	a3, a3, a2
-	rsr	a0, exccause
-	xsr	a3, ps
 
+	rsr	a2, exccause
+	bnei	a2, EXCCAUSE_LEVEL1_INTERRUPT, 1f
+	movi	a3, (1 << PS_WOE_BIT) | LOCKLEVEL
+1:
+	xsr	a3, ps
+	s32i	a2, a1, PT_EXCCAUSE
 	s32i	a3, a1, PT_PS		# save ps
 
 	/* Save lbeg, lend */
 
-	rsr	a2, lbeg
+	rsr	a4, lbeg
 	rsr	a3, lend
-	s32i	a2, a1, PT_LBEG
+	s32i	a4, a1, PT_LBEG
 	s32i	a3, a1, PT_LEND
 
 	/* Save SCOMPARE1 */
 
 #if XCHAL_HAVE_S32C1I
-	rsr     a2, scompare1
-	s32i    a2, a1, PT_SCOMPARE1
+	rsr     a3, scompare1
+	s32i    a3, a1, PT_SCOMPARE1
 #endif
 
 	/* Save optional registers. */
 
-	save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT
+	save_xtregs_opt a1 a3 a4 a5 a6 a7 PT_XTREGS_OPT
 	
 #ifdef CONFIG_TRACE_IRQFLAGS
 	l32i	a4, a1, PT_DEPC
@@ -391,8 +402,7 @@ common_exception:
 	 * while PS.EXCM was set, i.e. interrupts disabled.
 	 */
 	bgeui	a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
-	l32i	a4, a1, PT_EXCCAUSE
-	bnei	a4, EXCCAUSE_LEVEL1_INTERRUPT, 1f
+	bnei	a2, EXCCAUSE_LEVEL1_INTERRUPT, 1f
 	/* We came here with an interrupt means interrupts were enabled
 	 * and we've just disabled them.
 	 */
@@ -407,8 +417,8 @@ common_exception:
 
 	rsr	a4, excsave1
 	mov	a6, a1			# pass stack frame
-	mov	a7, a0			# pass EXCCAUSE
-	addx4	a4, a0, a4
+	mov	a7, a2			# pass EXCCAUSE
+	addx4	a4, a2, a4
 	l32i	a4, a4, EXC_TABLE_DEFAULT		# load handler
 
 	/* Call the second-level handler */
Signature · 1 line
1.8.1.4
maintainer
#4 lore raw

Re: [PATCH 2/8] xtensa: keep exception/interrupt stack continuous

Hi Max,

Not such a big fan about these changes as they introduce additional load and stores and a branch.

Copy spill area:
- is this only for debugging? Could the debugger identify the 'kernel exception' frame and handle it appropriately?
- if we need it for debugging/perf, maybe move these line under a kernel option (could be enabled by default)
- since we know the kernel stack frame size, why can't we just load from that offset (instead of the l32i and add). Also, can't we use s32e (need to look up the spec again).

Branch:
- is there any logical change in the code or are these only to avoid using a0?
- if for a0, couldn't we load a0 just before the 'xsr a3, ps' and keep the code as before?

Thanks,
-Chris

Quoted 140 lines · Max Filippov

Restore original a0 in the kernel exception stack frame. This way it looks like the frame that got interrupt/exception did alloca (copy a0 and a1 potentially spilled under old stack to the new location as well) to save registers and then did a call to handler. The point where interrupt/exception was taken is not in the stack chain, only in pt_regs (call4 from that address can be simulated to keep it in the stack trace).

---
 arch/xtensa/kernel/entry.S | 60 +++++++++++++++++++++++++++-------------------
 1 file changed, 35 insertions(+), 25 deletions(-)
arch/xtensa/kernel/entry.S +35 -26
index 82bbfa5..ab6a857 100644
@@ -218,7 +218,7 @@ _user_exception:
        /* We are back to the original stack pointer (a1) */
 
 2:     /* Now, jump to the common exception handler. */
-
+       movi    a0, 0                   # terminate user stack trace with 0
        j       common_exception
 
 ENDPROC(user_exception)
@@ -264,6 +264,19 @@ ENTRY(kernel_exception)
        .globl _kernel_exception
 _kernel_exception:
 
+       /* Copy spill slots of a0 and a1 to imitate movsp
+        * in order to keep exception stack continuous
+        */
+       l32i    a0, a1, PT_AREG1
+       addi    a2, a1, -16
+       addi    a0, a0, -16
+       l32i    a3, a0, 0
+       l32i    a0, a0, 4
+       s32i    a3, a2, 0
+       s32i    a0, a2, 4
+
+       l32i    a0, a1, PT_AREG0        # restore saved a0
+
        /* Save SAR and turn off single stepping */
 
        movi    a2, 0
@@ -338,52 +351,50 @@ common_exception:
        xsr     a2, lcount
        s32i    a2, a1, PT_LCOUNT
 
-       /* It is now save to restore the EXC_TABLE_FIXUP variable. */
+       /* It is now safe to restore the EXC_TABLE_FIXUP variable. */
 
-       rsr     a0, exccause
        movi    a3, 0
        rsr     a2, excsave1
-       s32i    a0, a1, PT_EXCCAUSE
        s32i    a3, a2, EXC_TABLE_FIXUP
 
-       /* All unrecoverable states are saved on stack, now, and a1 is valid,
-        * so we can allow exceptions and interrupts (*) again.
-        * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
+       /* Save remaining unrecoverable states (exccause, ps) on stack.
+        * Now we can allow exceptions again. In case we've got an interrupt
+        * PS.INTLEVEL is set to LOCKLEVEL disabling furhter interrupts,
+        * otherwise it's left unchanged.
         *
-        * (*) We only allow interrupts if they were previously enabled and
-        *     we're not handling an IRQ
+        * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
         */
 
        rsr     a3, ps
-       addi    a0, a0, -EXCCAUSE_LEVEL1_INTERRUPT
-       movi    a2, LOCKLEVEL
+       movi    a2, (1 << PS_WOE_BIT)
        extui   a3, a3, PS_INTLEVEL_SHIFT, PS_INTLEVEL_WIDTH
-                                       # a3 = PS.INTLEVEL
-       moveqz  a3, a2, a0              # a3 = LOCKLEVEL iff interrupt
-       movi    a2, 1 << PS_WOE_BIT
        or      a3, a3, a2
-       rsr     a0, exccause
-       xsr     a3, ps
 
+       rsr     a2, exccause
+       bnei    a2, EXCCAUSE_LEVEL1_INTERRUPT, 1f
+       movi    a3, (1 << PS_WOE_BIT) | LOCKLEVEL
+1:
+       xsr     a3, ps
+       s32i    a2, a1, PT_EXCCAUSE
        s32i    a3, a1, PT_PS           # save ps
 
        /* Save lbeg, lend */
 
-       rsr     a2, lbeg
+       rsr     a4, lbeg
        rsr     a3, lend
-       s32i    a2, a1, PT_LBEG
+       s32i    a4, a1, PT_LBEG
        s32i    a3, a1, PT_LEND
 
        /* Save SCOMPARE1 */
 
 #if XCHAL_HAVE_S32C1I
-       rsr     a2, scompare1
-       s32i    a2, a1, PT_SCOMPARE1
+       rsr     a3, scompare1
+       s32i    a3, a1, PT_SCOMPARE1
 #endif
 
        /* Save optional registers. */
 
-       save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT
+       save_xtregs_opt a1 a3 a4 a5 a6 a7 PT_XTREGS_OPT
 
 #ifdef CONFIG_TRACE_IRQFLAGS
        l32i    a4, a1, PT_DEPC
@@ -391,8 +402,7 @@ common_exception:
         * while PS.EXCM was set, i.e. interrupts disabled.
         */
        bgeui   a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
-       l32i    a4, a1, PT_EXCCAUSE
-       bnei    a4, EXCCAUSE_LEVEL1_INTERRUPT, 1f
+       bnei    a2, EXCCAUSE_LEVEL1_INTERRUPT, 1f
        /* We came here with an interrupt means interrupts were enabled
         * and we've just disabled them.
         */
@@ -407,8 +417,8 @@ common_exception:
 
        rsr     a4, excsave1
        mov     a6, a1                  # pass stack frame
-       mov     a7, a0                  # pass EXCCAUSE
-       addx4   a4, a0, a4
+       mov     a7, a2                  # pass EXCCAUSE
+       addx4   a4, a2, a4
        l32i    a4, a4, EXC_TABLE_DEFAULT               # load handler
 
        /* Call the second-level handler */
--

1.8.1.4

author maintainer
#5 lore raw

Re: [PATCH 2/8] xtensa: keep exception/interrupt stack continuous

Hi Chris,

Quoted 6 lines · Chris Zankel

Not such a big fan about these changes as they introduce additional load and stores and a branch.

Copy spill area:
- is this only for debugging? Could the debugger identify the 'kernel exception' frame and handle it appropriately?

For the debugger and all in-kernel stack tracers: perf, ftrace, oprofile. I'm not sure how the kernel exception frame can be identified, especially for the nested kernel re-entries.

Quoted 2 lines

- if we need it for debugging/perf, maybe move these line under a kernel option (could be enabled by default)

Ok.

Quoted 3 lines

- since we know the kernel stack frame size, why can't we just load from that offset (instead of the l32i and add). Also, can't we use s32e (need to look up the spec again).

Oh, right, l32e and s32e make perfect sense here, I thought about it, but somehow I was under impression we could get here from userspace and CRING would be wrong for the kernel stack. We obviously can't.

Quoted 2 lines

Branch:
- is there any logical change in the code or are these only to avoid using a0?

Yes.

Quoted 2 lines

- if for a0, couldn't we load a0 just before the 'xsr a3, ps' and keep the code as before?

Sure.

Signature · 2 lines
Thanks.
-- Max
author maintainer
#6 lore raw

Re: [PATCH 2/8] xtensa: keep exception/interrupt stack continuous

Quoted 4 lines · Max Filippov
Quoted 2 lines

Branch:
- is there any logical change in the code or are these only to avoid using a0?

Yes.

Meant the latter.

Signature · 2 lines
Thanks.
-- Max
author maintainer
#7 lore raw

PATCH 3/8 xtensa: move oprofile stack tracing to stacktrace.c

In reply to Max Filippov

Old oprofile interface will share user stack tracing with new perf interface. Move oprofile user/kernel stack tracing to stacktrace.c to make it possible.

---
 arch/xtensa/include/asm/stacktrace.h |   8 ++
 arch/xtensa/kernel/stacktrace.c      | 167 ++++++++++++++++++++++++++++++++++-
 arch/xtensa/oprofile/backtrace.c     | 158 ++-------------------------------
 3 files changed, 182 insertions(+), 151 deletions(-)
arch/xtensa/include/asm/stacktrace.h +8 -0
index 6a05fcb..fe06e8e 100644
@@ -33,4 +33,12 @@ void walk_stackframe(unsigned long *sp,
 		int (*fn)(struct stackframe *frame, void *data),
 		void *data);
 
+void xtensa_backtrace_kernel(struct pt_regs *regs, unsigned int depth,
+			     int (*kfn)(struct stackframe *frame, void *data),
+			     int (*ufn)(struct stackframe *frame, void *data),
+			     void *data);
+void xtensa_backtrace_user(struct pt_regs *regs, unsigned int depth,
+			   int (*ufn)(struct stackframe *frame, void *data),
+			   void *data);
+
 #endif /* _XTENSA_STACKTRACE_H */
arch/xtensa/kernel/stacktrace.c +166 -1

183 lines not on this page · raw message

arch/xtensa/oprofile/backtrace.c +8 -150

176 lines not on this page · raw message

Signature · 1 line
1.8.1.4
author maintainer
#8 lore raw

PATCH 4/8 xtensa: select PERF_USE_VMALLOC for cache-aliasing configurations

In reply to Max Filippov
---
 arch/xtensa/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/xtensa/Kconfig +1 -0
index ba22699..3c57934 100644
@@ -20,6 +20,7 @@ config XTENSA
 	select HAVE_PERF_EVENTS
 	select IRQ_DOMAIN
 	select MODULES_USE_ELF_RELA
+	select PERF_USE_VMALLOC
 	select VIRT_TO_BUS
 	help
 	  Xtensa processors are 32-bit RISC machines designed by Tensilica
Signature · 1 line
1.8.1.4
author maintainer
#9 lore raw

PATCH 5/8 xtensa: add profiling IRQ type to xtensa_irq_map

In reply to Max Filippov
---
 arch/xtensa/kernel/irq.c | 6 ++++++
 1 file changed, 6 insertions(+)
arch/xtensa/kernel/irq.c +6 -0
index 3eee94f..32b6056 100644
@@ -106,6 +106,12 @@ int xtensa_irq_map(struct irq_domain *d, unsigned int irq,
 		irq_set_chip_and_handler_name(irq, irq_chip,
 				handle_percpu_irq, "timer");
 		irq_clear_status_flags(irq, IRQ_LEVEL);
+#ifdef XCHAL_INTTYPE_MASK_PROFILING
+	} else if (mask & XCHAL_INTTYPE_MASK_PROFILING) {
+		irq_set_chip_and_handler_name(irq, irq_chip,
+				handle_percpu_irq, "profiling");
+		irq_set_status_flags(irq, IRQ_LEVEL);
+#endif
 	} else {/* XCHAL_INTTYPE_MASK_WRITE_ERROR */
 		/* XCHAL_INTTYPE_MASK_NMI */
 		irq_set_chip_and_handler_name(irq, irq_chip,
Signature · 1 line
1.8.1.4
author maintainer
#10 lore raw

PATCH 6/8 xtensa: count software page fault perf events

In reply to Max Filippov
---
 arch/xtensa/mm/fault.c | 7 +++++++
 1 file changed, 7 insertions(+)
arch/xtensa/mm/fault.c +7 -0
index 9e3571a..76360a2 100644
@@ -15,6 +15,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/hardirq.h>
+#include <linux/perf_event.h>
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
 #include <asm/hardirq.h>
@@ -142,6 +143,12 @@ good_area:
 	}
 
 	up_read(&mm->mmap_sem);
+	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
+	if (flags & VM_FAULT_MAJOR)
+		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, address);
+	else if (flags & VM_FAULT_MINOR)
+		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address);
+
 	return;
 
 	/* Something tried to access memory that isn't in our memory map..
Signature · 1 line
1.8.1.4
author maintainer
#11 lore raw

PATCH 7/8 xtensa: implement counting and sampling perf events

In reply to Max Filippov

Xtensa Performance Monitor Module has up to 8 32 bit wide performance counters. Each counter may be enabled independently and can count any single type of hardware performance events. Event counting may be enabled and disabled globally (per PMM).
Each counter has status register with bits indicating if the counter has been overflown and may be programmed to raise profiling IRQ on overflow. This IRQ is used to rewind counters and allow for counting more than 2^32 samples for counting events and to report samples for sampling events.

For more details see Tensilica Debug User's Guide, chapter 8 "Performance monitor module".

Cc Peter Zijlstra <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
---
 arch/xtensa/Kconfig             |  10 +
 arch/xtensa/kernel/Makefile     |   1 +
 arch/xtensa/kernel/perf_event.c | 450 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 461 insertions(+)
 create mode 100644 arch/xtensa/kernel/perf_event.c
arch/xtensa/Kconfig +10 -0
index 3c57934..0e92885 100644
@@ -126,6 +126,16 @@ config XTENSA_VARIANT_MMU
 	  Build a Conventional Kernel with full MMU support,
 	  ie: it supports a TLB with auto-loading, page protection.
 
+config XTENSA_VARIANT_HAVE_PERF_EVENTS
+	bool "Core variant has Performance Monitor Module"
+	depends on XTENSA_VARIANT_CUSTOM
+	default n
+	help
+	  Enable if core variant has Performance Monitor Module with
+	  External Registers Interface.
+
+	  If unsure, say N.
+
 config XTENSA_UNALIGNED_USER
 	bool "Unaligned memory access in use space"
 	help
arch/xtensa/kernel/Makefile +1 -0
index d3a0f0f..547a757 100644
@@ -13,6 +13,7 @@ obj-$(CONFIG_PCI) += pci.o
 obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o
 obj-$(CONFIG_FUNCTION_TRACER) += mcount.o
 obj-$(CONFIG_SMP) += smp.o mxhead.o
+obj-$(CONFIG_XTENSA_VARIANT_HAVE_PERF_EVENTS) += perf_event.o
 
 AFLAGS_head.o += -mtext-section-literals
 
arch/xtensa/kernel/perf_event.c new file +450 -0

450 lines not on this page · raw message

Signature · 1 line
1.8.1.4
maintainer
#12 lore raw

Re: [PATCH 7/8] xtensa: implement counting and sampling perf events

Quoted 21 lines · Max Filippov
arch/xtensa/kernel/perf_event.c new file +21 -0
+static int xtensa_pmu_event_init(struct perf_event *event)
+{
+	int ret;
+
+	switch (event->attr.type) {
+	case PERF_TYPE_HARDWARE:
+		if (event->attr.config >= ARRAY_SIZE(xtensa_hw_ctl) ||
+		    xtensa_hw_ctl[event->attr.config] == 0)
+			return -ENOENT;
+		event->hw.config = xtensa_hw_ctl[event->attr.config];
+		return 0;
+
+	case PERF_TYPE_HW_CACHE:
+		ret = xtensa_pmu_cache_event(event->attr.config);
+		if (ret < 0)
+			return ret;
+		event->hw.config = ret;
+		return 0;
+
+	case PERF_TYPE_RAW:
+		/* Not 'previous counter' select */

arch/xtensa/kernel/perf_event.c line 231

Quoted 10 lines
arch/xtensa/kernel/perf_event.c new file +10 -0
+		if ((event->attr.config & XTENSA_PMU_PMCTRL_SELECT) ==
+		    (1 << XTENSA_PMU_PMCTRL_SELECT_SHIFT))
+			return -ENOENT;
+		event->hw.config = (event->attr.config &
+				    (XTENSA_PMU_PMCTRL_KRNLCNT |
+				     XTENSA_PMU_PMCTRL_TRACELEVEL |
+				     XTENSA_PMU_PMCTRL_SELECT |
+				     XTENSA_PMU_PMCTRL_MASK)) |
+			XTENSA_PMU_PMCTRL_INTEN;
+		return 0;

Since this PMU implements TYPE_HARDWARE/TYPE_HW_CACHE/TYPE_RAW, returning -ENOENT for those is wrong.

If the configuration is invalid, return -EINVAL.

Quoted 5 lines
arch/xtensa/kernel/perf_event.c new file +5 -0
+
+	default:
+		return -ENOENT;
+	}
+}
author maintainer
#13 lore raw

Re: [PATCH 7/8] xtensa: implement counting and sampling perf events

Quoted 4 lines · Peter Zijlstra

Since this PMU implements TYPE_HARDWARE/TYPE_HW_CACHE/TYPE_RAW, returning -ENOENT for those is wrong.

If the configuration is invalid, return -EINVAL.

Ok.

Signature · 2 lines
Thanks.
-- Max
maintainer
#14 lore raw

Re: [PATCH 7/8] xtensa: implement counting and sampling perf events

In reply to Max Filippov

arch/xtensa/kernel/perf_event.c line 436

Quoted 4 lines · Max Filippov
arch/xtensa/kernel/perf_event.c new file +4 -0
+static int __init xtensa_pmu_init(void)
+{
+	int ret;
+	int irq = irq_create_mapping(NULL, XCHAL_PROFILING_INTERRUPT);

Does this platform have interrupt priorities which you can partially mask in order to create NMI like behaviour?

author maintainer
#15 lore raw

Re: [PATCH 7/8] xtensa: implement counting and sampling perf events

Quoted 8 lines · Peter Zijlstra

arch/xtensa/kernel/perf_event.c line 436

Quoted 4 lines · Max Filippov
arch/xtensa/kernel/perf_event.c new file +4 -0
+static int __init xtensa_pmu_init(void)
+{
+     int ret;
+     int irq = irq_create_mapping(NULL, XCHAL_PROFILING_INTERRUPT);

Does this platform have interrupt priorities which you can partially mask in order to create NMI like behaviour?

Not sure what you mean by "NMI like".
Interrupt priorities are fixed in the current xtensa architecture, and we can in theory
mask certain level and below, but practically we always mask all low- and medium-
level interrupts.

Also we currently can't have handlers for high priority interrupts written in C.

Signature · 2 lines
Thanks.
-- Max
maintainer
#16 lore raw

Re: [PATCH 7/8] xtensa: implement counting and sampling perf events

Quoted 11 lines · Max Filippov
Quoted 8 lines · Peter Zijlstra

arch/xtensa/kernel/perf_event.c line 436

Quoted 4 lines · Max Filippov
arch/xtensa/kernel/perf_event.c new file +4 -0
+static int __init xtensa_pmu_init(void)
+{
+     int ret;
+     int irq = irq_create_mapping(NULL, XCHAL_PROFILING_INTERRUPT);

Does this platform have interrupt priorities which you can partially mask in order to create NMI like behaviour?

Not sure what you mean by "NMI like".

There's a number of archs where we implement NMIs by having local_irq_disable() only disable part of the interrupt priority range and making sure all 'normal' IRQs are mapped in that priority range.

We then map our NMI handlers to a priority above the 'normal' range, such that these interrupts can indeed happen when interrupts are 'disabled.

See for example:

b4f4372f96e0 ("sparc64: Make %pil level 15 a pseudo-NMI.") 0c25e9e6cbe7 ("sparc64: Adjust __raw_local_irq_save() to cooperate in NMIs.") c011f80ba091 ("sparc64: Add some more commentary to __raw_local_irq_save()")

Quoted 5 lines

Interrupt priorities are fixed in the current xtensa architecture, and we can in theory mask certain level and below, but practically we always mask all low- and medium- level interrupts.

Also we currently can't have handlers for high priority interrupts written in C.

Why not? Surely this can be cured with an assembly stub?

The advantage of having NMIs is that profiling information for the kernel becomes much more useful. Without this local_irq_enable() will be a very 'hot' function.

author maintainer
#17 lore raw

Re: [PATCH 7/8] xtensa: implement counting and sampling perf events

Quoted 21 lines · Peter Zijlstra
Quoted 11 lines · Max Filippov
Quoted 8 lines · Peter Zijlstra

arch/xtensa/kernel/perf_event.c line 436

Quoted 4 lines · Max Filippov
arch/xtensa/kernel/perf_event.c new file +4 -0
+static int __init xtensa_pmu_init(void)
+{
+     int ret;
+     int irq = irq_create_mapping(NULL, XCHAL_PROFILING_INTERRUPT);

Does this platform have interrupt priorities which you can partially mask in order to create NMI like behaviour?

Not sure what you mean by "NMI like".

There's a number of archs where we implement NMIs by having local_irq_disable() only disable part of the interrupt priority range and making sure all 'normal' IRQs are mapped in that priority range.

We then map our NMI handlers to a priority above the 'normal' range, such that these interrupts can indeed happen when interrupts are 'disabled.

Quoted 5 lines

See for example:

b4f4372f96e0 ("sparc64: Make %pil level 15 a pseudo-NMI.") 0c25e9e6cbe7 ("sparc64: Adjust __raw_local_irq_save() to cooperate in NMIs.") c011f80ba091 ("sparc64: Add some more commentary to __raw_local_irq_save()")

Ok, I see. I guess I can change IRQ disabling logic to not mask perf IRQ in case it's configured as the only interrupt on its level and it's the highest medium-level IRQ.

Quoted 7 lines
Quoted 5 lines

Interrupt priorities are fixed in the current xtensa architecture, and we can in theory mask certain level and below, but practically we always mask all low- and medium- level interrupts.

Also we currently can't have handlers for high priority interrupts written in C.

Why not? Surely this can be cured with an assembly stub?

IIUC that was a deliberate architecture design choice and working around it penalizes all interrupt handlers. But let me take another close look.

Quoted 3 lines

The advantage of having NMIs is that profiling information for the kernel becomes much more useful. Without this local_irq_enable() will be a very 'hot' function.

I haven't noticed that in my testing.

Signature · 2 lines
Thanks.
-- Max
maintainer
#18 lore raw

Re: [PATCH 7/8] xtensa: implement counting and sampling perf events

Hi Max,

We could probably still use NMI with a separate stack. However, for exception handling while in NMI, we might have to implement something similar to x86_64 (https://lwn.net/Articles/484932/).

Cheers!
-Chris

Quoted 52 lines · Max Filippov
Quoted 21 lines · Peter Zijlstra
Quoted 11 lines · Max Filippov
Quoted 8 lines · Peter Zijlstra

arch/xtensa/kernel/perf_event.c line 436

Quoted 4 lines · Max Filippov
arch/xtensa/kernel/perf_event.c new file +4 -0
+static int __init xtensa_pmu_init(void)
+{
+     int ret;
+     int irq = irq_create_mapping(NULL, XCHAL_PROFILING_INTERRUPT);

Does this platform have interrupt priorities which you can partially mask in order to create NMI like behaviour?

Not sure what you mean by "NMI like".

There's a number of archs where we implement NMIs by having local_irq_disable() only disable part of the interrupt priority range and making sure all 'normal' IRQs are mapped in that priority range.

We then map our NMI handlers to a priority above the 'normal' range, such that these interrupts can indeed happen when interrupts are 'disabled.

Quoted 5 lines

See for example:

b4f4372f96e0 ("sparc64: Make %pil level 15 a pseudo-NMI.") 0c25e9e6cbe7 ("sparc64: Adjust __raw_local_irq_save() to cooperate in NMIs.") c011f80ba091 ("sparc64: Add some more commentary to __raw_local_irq_save()")

Ok, I see. I guess I can change IRQ disabling logic to not mask perf IRQ in case it's configured as the only interrupt on its level and it's the highest medium-level IRQ.

Quoted 7 lines
Quoted 5 lines

Interrupt priorities are fixed in the current xtensa architecture, and we can in theory mask certain level and below, but practically we always mask all low- and medium- level interrupts.

Also we currently can't have handlers for high priority interrupts written in C.

Why not? Surely this can be cured with an assembly stub?

IIUC that was a deliberate architecture design choice and working around it penalizes all interrupt handlers. But let me take another close look.

Quoted 3 lines

The advantage of having NMIs is that profiling information for the kernel becomes much more useful. Without this local_irq_enable() will be a very 'hot' function.

I haven't noticed that in my testing.

--
Thanks.
-- Max

author maintainer
#19 lore raw

PATCH 8/8 perf tools: xtensa: add DWARF register names

In reply to Max Filippov
Cc Peter Zijlstra <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
---
 tools/perf/arch/xtensa/Build             |  1 +
 tools/perf/arch/xtensa/Makefile          |  3 +++
 tools/perf/arch/xtensa/util/Build        |  1 +
 tools/perf/arch/xtensa/util/dwarf-regs.c | 25 +++++++++++++++++++++++++
 4 files changed, 30 insertions(+)
 create mode 100644 tools/perf/arch/xtensa/Build
 create mode 100644 tools/perf/arch/xtensa/Makefile
 create mode 100644 tools/perf/arch/xtensa/util/Build
 create mode 100644 tools/perf/arch/xtensa/util/dwarf-regs.c
tools/perf/arch/xtensa/Build new file +1 -0
new file mode 100644
index 0000000..54afe4a
@@ -0,0 +1 @@
+libperf-y += util/
tools/perf/arch/xtensa/Makefile new file +3 -0
new file mode 100644
index 0000000..7fbca17
@@ -0,0 +1,3 @@
+ifndef NO_DWARF
+PERF_HAVE_DWARF_REGS := 1
+endif
tools/perf/arch/xtensa/util/Build new file +1 -0
new file mode 100644
index 0000000..954e287
@@ -0,0 +1 @@
+libperf-$(CONFIG_DWARF) += dwarf-regs.o
tools/perf/arch/xtensa/util/dwarf-regs.c new file +25 -0
new file mode 100644
index 0000000..4dba76b
@@ -0,0 +1,25 @@
+/*
+ * Mapping of DWARF debug register numbers into register names.
+ *
+ * Copyright (c) 2015 Cadence Design Systems Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <stddef.h>
+#include <dwarf-regs.h>
+
+#define XTENSA_MAX_REGS 16
+
+const char *xtensa_regs_table[XTENSA_MAX_REGS] = {
+	"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
+	"a8", "a9", "a10", "a11", "a12", "a13", "a14", "a15",
+};
+
+const char *get_arch_regstr(unsigned int n)
+{
+	return n < XTENSA_MAX_REGS ? xtensa_regs_table[n] : NULL;
+}
Signature · 1 line
1.8.1.4