From d2108bf0841e0768e600336cc8aabb2a51ca9fa3 Mon Sep 17 00:00:00 2001 From: Yonattan Louise Date: Fri, 21 Aug 2015 19:10:32 -0500 Subject: [PATCH] Profile interrupt events. Add the interrupt profile points for x86 and ARM arquitectures. This gives information regarding the time when interrupts occur. Change-Id: Ic876c0e7f9e8819d53e0578416f09146f4456d3d Signed-off-by: Yonattan Louise --- arch/arc/defconfig | 1 + arch/arm/core/isr_wrapper.S | 6 +++ arch/arm/defconfig | 1 + arch/arm/include/profiler_arch.h | 54 ++++++++++++++++++++++ arch/x86/core/intstub.S | 9 ++++ arch/x86/defconfig | 1 + arch/x86/include/profiler_arch.h | 54 ++++++++++++++++++++++ drivers/interrupt_controller/loapic_intr.c | 43 +++++++++++++++++ drivers/timer/cortex_m_systick.c | 6 +++ include/misc/profiler.h | 4 ++ kernel/Kconfig | 10 ++++ kernel/nanokernel/profiler.c | 14 ++++++ 12 files changed, 203 insertions(+) create mode 100644 arch/arm/include/profiler_arch.h create mode 100644 arch/x86/include/profiler_arch.h diff --git a/arch/arc/defconfig b/arch/arc/defconfig index 8e111adefed..1eb306e8534 100644 --- a/arch/arc/defconfig +++ b/arch/arc/defconfig @@ -17,6 +17,7 @@ CONFIG_XIP=y # CONFIG_KERNEL_PROFILER is not set # CONFIG_PROFILER_BUFFER_SIZE is not set # CONFIG_PROFILER_CONTEXT_SWITCH is not set +# CONFIG_PROFILER_INTERRUPT is not set # # Nanokernel Options diff --git a/arch/arm/core/isr_wrapper.S b/arch/arm/core/isr_wrapper.S index f7fd7b552cc..1ad919ae22d 100644 --- a/arch/arm/core/isr_wrapper.S +++ b/arch/arm/core/isr_wrapper.S @@ -72,6 +72,12 @@ SECTION_FUNC(TEXT, _isr_wrapper) push {lr} /* lr is now the first item on the stack */ +#ifdef CONFIG_PROFILER_INTERRUPT + push {lr} + bl _sys_profiler_interrupt + pop {lr} +#endif + #ifdef CONFIG_ADVANCED_POWER_MANAGEMENT /* * All interrupts are disabled when handling idle wakeup. For tickless diff --git a/arch/arm/defconfig b/arch/arm/defconfig index 62c5628b529..094cd391619 100644 --- a/arch/arm/defconfig +++ b/arch/arm/defconfig @@ -18,6 +18,7 @@ CONFIG_XIP=y # CONFIG_KERNEL_PROFILER is not set # CONFIG_PROFILER_BUFFER_SIZE is not set # CONFIG_PROFILER_CONTEXT_SWITCH is not set +# CONFIG_PROFILER_INTERRUPT is not set # # Nanokernel Options diff --git a/arch/arm/include/profiler_arch.h b/arch/arm/include/profiler_arch.h new file mode 100644 index 00000000000..1047250a4eb --- /dev/null +++ b/arch/arm/include/profiler_arch.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3) Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * @file + * @brief Profiler support for ARM + */ + +#ifndef __PROFILE_ARM_H__ +#define __PROFILE_ARM_H__ + +#include + +/** + * @brief Get the identification of the current interrupt. + * + * This routine obtain the key of the interrupt that is currently processed + * if it is called from a ISR context. + * + * @return The key of the interrupt that is currently being processed. + */ +int _sys_current_irq_key_get(void) +{ + return _IpsrGet(); +} + +#endif /* __PROFILE_ARM_H__ */ diff --git a/arch/x86/core/intstub.S b/arch/x86/core/intstub.S index 8add40c842e..05b53427fc1 100644 --- a/arch/x86/core/intstub.S +++ b/arch/x86/core/intstub.S @@ -170,6 +170,15 @@ SECTION_FUNC(TEXT, _IntEnt) popl %eax #endif +#ifdef CONFIG_PROFILER_INTERRUPT + /* + * Preserve EAX as it contains the stub return address. + */ + pushl %eax + call _sys_profiler_interrupt + popl %eax +#endif + /* load %ecx with &_nanokernel */ diff --git a/arch/x86/defconfig b/arch/x86/defconfig index 5d7a27ccf70..6d8d8f375ee 100644 --- a/arch/x86/defconfig +++ b/arch/x86/defconfig @@ -20,6 +20,7 @@ CONFIG_ENHANCED_SECURITY=y # CONFIG_KERNEL_PROFILER is not set # CONFIG_PROFILER_BUFFER_SIZE is not set # CONFIG_PROFILER_CONTEXT_SWITCH is not set +# CONFIG_PROFILER_INTERRUPT is not set # # Security Options diff --git a/arch/x86/include/profiler_arch.h b/arch/x86/include/profiler_arch.h new file mode 100644 index 00000000000..21b0a647d8b --- /dev/null +++ b/arch/x86/include/profiler_arch.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3) Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * @file + * @brief Profiler support for x86 + */ + +#ifndef __PROFILE_X86_H__ +#define __PROFILE_X86_H__ + +/** + * @brief Get the identification of the current interrupt. + * + * This routine obtain the key of the interrupt that is currently processed + * if it is called from a ISR context. + * + * @return The key of the interrupt that is currently being processed. + */ +int _sys_current_irq_key_get(void) +{ + extern int _loapic_isr_vector_get(void); + + return _loapic_isr_vector_get(); +} + +#endif /* __PROFILE_X86_H__ */ diff --git a/drivers/interrupt_controller/loapic_intr.c b/drivers/interrupt_controller/loapic_intr.c index 16b89cd0901..2c146be8760 100644 --- a/drivers/interrupt_controller/loapic_intr.c +++ b/drivers/interrupt_controller/loapic_intr.c @@ -416,3 +416,46 @@ void _loapic_irq_disable(unsigned int irq /* IRQ number of the *pLvt = *pLvt | LOAPIC_LVT_MASKED; irq_unlock(oldLevel); } + + +/** + * @brief Find the currently executing interrupt vector, if any + * + * This routine finds the vector of the interrupt that is being processed. + * The ISR (In-Service Register) register contain the vectors of the interrupts + * in service. And the higher vector is the indentification of the interrupt + * being currently processed. + * + * ISR registers' offsets: + * -------------------- + * | Offset | bits | + * -------------------- + * | 0100H | 0:31 | + * | 0110H | 32:63 | + * | 0120H | 64:95 | + * | 0130H | 96:127 | + * | 0140H | 128:159 | + * | 0150H | 160:191 | + * | 0160H | 192:223 | + * | 0170H | 224:255 | + * -------------------- + * + * @return The vector of the interrupt that is currently being processed. + */ +int _loapic_isr_vector_get(void) +{ + /* pointer to ISR vector table */ + volatile int *pReg; + int block=0; + + while (block < 8) { + pReg = (volatile int *) + (CONFIG_LOAPIC_BASE_ADDRESS + LOAPIC_ISR + (block * 0x10)); + if (*pReg) { + return (block * 32) + (find_lsb_set(*pReg) - 1); + } + block++; + } + + return 0; +} diff --git a/drivers/timer/cortex_m_systick.c b/drivers/timer/cortex_m_systick.c index 37f4b378a01..26c595f50a5 100644 --- a/drivers/timer/cortex_m_systick.c +++ b/drivers/timer/cortex_m_systick.c @@ -263,6 +263,12 @@ void _TIMER_INT_HANDLER(void *unused) { ARG_UNUSED(unused); +#ifdef CONFIG_PROFILER_INTERRUPT + extern void _sys_profiler_interrupt(void); + _sys_profiler_interrupt(); +#endif + + #ifdef CONFIG_INT_LATENCY_BENCHMARK uint32_t value = __scs.systick.val; uint32_t delta = __scs.systick.reload - value; diff --git a/include/misc/profiler.h b/include/misc/profiler.h index 3755a055fa8..d1a4b85fd6a 100644 --- a/include/misc/profiler.h +++ b/include/misc/profiler.h @@ -45,6 +45,10 @@ #define PROFILER_CONTEXT_SWITCH_EVENT_ID 0x0001 #endif +#ifdef CONFIG_PROFILER_INTERRUPT +#define PROFILER_INTERRUPT_EVENT_ID 0x0002 +#endif + #ifndef _ASMLANGUAGE /** * Global variable of the ring buffer that allows user to implement diff --git a/kernel/Kconfig b/kernel/Kconfig index 236e89a8026..7ce0caff263 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -140,6 +140,16 @@ config PROFILER_CONTEXT_SWITCH depends on KERNEL_PROFILER help Enable the context switch event messages. + +config PROFILER_INTERRUPT + bool + prompt "Interrupt profiler point" + default n + depends on KERNEL_PROFILER + help + Enable interrupt event messages. These messages provide the following + information: The time when interrupts occur. + endmenu menu "Security Options" diff --git a/kernel/nanokernel/profiler.c b/kernel/nanokernel/profiler.c index 69f55581512..0ebe45ef7fc 100644 --- a/kernel/nanokernel/profiler.c +++ b/kernel/nanokernel/profiler.c @@ -38,6 +38,7 @@ #include #include #include +#include uint32_t _sys_profiler_buffer[CONFIG_PROFILER_BUFFER_SIZE]; @@ -120,3 +121,16 @@ void sys_profiler_register_as_collector(void) _collector_fiber = _nanokernel.current; } #endif /* CONFIG_PROFILER_CONTEXT_SWITCH */ + + +#ifdef CONFIG_PROFILER_INTERRUPT +void _sys_profiler_interrupt() +{ + uint32_t data[2]; + + data[0] = nano_tick_get_32(); + data[1] = _sys_current_irq_key_get(); + + sys_profiler_put(PROFILER_INTERRUPT_EVENT_ID, data, ARRAY_SIZE(data)); +} +#endif /* CONFIG_PROFILER_INTERRUPT */