From 5c6ef8fdb57e1fc5d5170b6fd493ecfc24d8aed8 Mon Sep 17 00:00:00 2001 From: Yonattan Louise Date: Fri, 21 Aug 2015 19:15:26 -0500 Subject: [PATCH] Profile low condition events. Add the sleep events point for x86 and ARM arquitectures that gives information about when the CPU went to sleep mode, when it woke up and which interrupt causes the CPU to awake. Change-Id: Iaa06a678eab661357d084ee1f79c4cfcf19bf85d Signed-off-by: Yonattan Louise --- arch/arc/defconfig | 1 + arch/arm/core/cpu_idle.S | 11 +++++++++++ arch/arm/defconfig | 1 + arch/x86/core/cpuhalt.S | 6 ++++++ arch/x86/defconfig | 1 + include/misc/profiler.h | 4 ++++ kernel/Kconfig | 11 +++++++++++ kernel/microkernel/k_idle.c | 4 ++++ kernel/nanokernel/profiler.c | 25 +++++++++++++++++++++++++ 9 files changed, 64 insertions(+) diff --git a/arch/arc/defconfig b/arch/arc/defconfig index 1eb306e8534..5147264f5db 100644 --- a/arch/arc/defconfig +++ b/arch/arc/defconfig @@ -18,6 +18,7 @@ CONFIG_XIP=y # CONFIG_PROFILER_BUFFER_SIZE is not set # CONFIG_PROFILER_CONTEXT_SWITCH is not set # CONFIG_PROFILER_INTERRUPT is not set +# CONFIG_PROFILER_SLEEP is not set # # Nanokernel Options diff --git a/arch/arm/core/cpu_idle.S b/arch/arm/core/cpu_idle.S index fc51f1f39ad..ff24c06133c 100644 --- a/arch/arm/core/cpu_idle.S +++ b/arch/arm/core/cpu_idle.S @@ -134,6 +134,12 @@ SECTION_FUNC(TEXT, _NanoIdleValClear) */ SECTION_FUNC(TEXT, nano_cpu_idle) +#ifdef CONFIG_PROFILER_SLEEP + push {lr} + bl _sys_profiler_enter_sleep + pop {lr} +#endif + /* clear BASEPRI so wfi is awakened by incoming interrupts */ eors.n r0, r0 msr BASEPRI, r0 @@ -169,6 +175,11 @@ SECTION_FUNC(TEXT, nano_cpu_idle) */ SECTION_FUNC(TEXT, nano_cpu_atomic_idle) +#ifdef CONFIG_PROFILER_SLEEP + push {lr} + bl _sys_profiler_enter_sleep + pop {lr} +#endif /* * r0: interrupt mask from caller diff --git a/arch/arm/defconfig b/arch/arm/defconfig index 094cd391619..8317f8b3058 100644 --- a/arch/arm/defconfig +++ b/arch/arm/defconfig @@ -19,6 +19,7 @@ CONFIG_XIP=y # CONFIG_PROFILER_BUFFER_SIZE is not set # CONFIG_PROFILER_CONTEXT_SWITCH is not set # CONFIG_PROFILER_INTERRUPT is not set +# CONFIG_PROFILER_SLEEP is not set # # Nanokernel Options diff --git a/arch/x86/core/cpuhalt.S b/arch/x86/core/cpuhalt.S index a4ff9a5d224..f42377f1bd5 100644 --- a/arch/x86/core/cpuhalt.S +++ b/arch/x86/core/cpuhalt.S @@ -84,6 +84,9 @@ SECTION_FUNC(TEXT, nano_cpu_idle) #ifdef CONFIG_INT_LATENCY_BENCHMARK call _int_latency_stop #endif +#ifdef CONFIG_PROFILER_SLEEP + call _sys_profiler_enter_sleep +#endif #if defined(CONFIG_BOOT_TIME_MEASUREMENT) rdtsc /* record idle timestamp */ mov %eax, __idle_tsc /* ... low 32 bits */ @@ -123,6 +126,9 @@ SECTION_FUNC(TEXT, nano_cpu_idle) SECTION_FUNC(TEXT, nano_cpu_atomic_idle) #ifdef CONFIG_INT_LATENCY_BENCHMARK call _int_latency_stop +#endif +#ifdef CONFIG_PROFILER_SLEEP + call _sys_profiler_enter_sleep #endif sti /* make sure interrupts are enabled */ diff --git a/arch/x86/defconfig b/arch/x86/defconfig index 6d8d8f375ee..3f8471011be 100644 --- a/arch/x86/defconfig +++ b/arch/x86/defconfig @@ -21,6 +21,7 @@ CONFIG_ENHANCED_SECURITY=y # CONFIG_PROFILER_BUFFER_SIZE is not set # CONFIG_PROFILER_CONTEXT_SWITCH is not set # CONFIG_PROFILER_INTERRUPT is not set +# CONFIG_PROFILER_SLEEP is not set # # Security Options diff --git a/include/misc/profiler.h b/include/misc/profiler.h index d1a4b85fd6a..dac14c7a803 100644 --- a/include/misc/profiler.h +++ b/include/misc/profiler.h @@ -49,6 +49,10 @@ #define PROFILER_INTERRUPT_EVENT_ID 0x0002 #endif +#ifdef CONFIG_PROFILER_SLEEP +#define PROFILER_SLEEP_EVENT_ID 0x0003 +#endif + #ifndef _ASMLANGUAGE /** * Global variable of the ring buffer that allows user to implement diff --git a/kernel/Kconfig b/kernel/Kconfig index 7ce0caff263..494e8760597 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -150,6 +150,17 @@ config PROFILER_INTERRUPT Enable interrupt event messages. These messages provide the following information: The time when interrupts occur. +config PROFILER_SLEEP + bool + prompt "Sleep profiler point" + default n + depends on KERNEL_PROFILER && ADVANCED_POWER_MANAGEMENT + help + Enable low power condition event messages. These messages provide the + following information: + - When the CPU went to sleep mode. + - When the CPU woke up. + - The ID of the interrupt that woke the CPU up. endmenu menu "Security Options" diff --git a/kernel/microkernel/k_idle.c b/kernel/microkernel/k_idle.c index 2a5faf76a2a..aa66ca4ad1f 100644 --- a/kernel/microkernel/k_idle.c +++ b/kernel/microkernel/k_idle.c @@ -370,6 +370,10 @@ void _sys_power_save_idle_exit(int32_t ticks) #else ARG_UNUSED(ticks); #endif /* CONFIG_TICKLESS_IDLE */ +#ifdef CONFIG_PROFILER_SLEEP + extern void _sys_profiler_exit_sleep(void); + _sys_profiler_exit_sleep(); +#endif } /** diff --git a/kernel/nanokernel/profiler.c b/kernel/nanokernel/profiler.c index 0ebe45ef7fc..aca41259a71 100644 --- a/kernel/nanokernel/profiler.c +++ b/kernel/nanokernel/profiler.c @@ -46,6 +46,11 @@ uint32_t _sys_profiler_buffer[CONFIG_PROFILER_BUFFER_SIZE]; void *_collector_fiber=NULL; #endif +#ifdef CONFIG_PROFILER_SLEEP +uint32_t _sys_profiler_sleep_start_time; +#endif + + /** * @brief Initialize the profiler system. * @@ -134,3 +139,23 @@ void _sys_profiler_interrupt() sys_profiler_put(PROFILER_INTERRUPT_EVENT_ID, data, ARRAY_SIZE(data)); } #endif /* CONFIG_PROFILER_INTERRUPT */ + + +#ifdef CONFIG_PROFILER_SLEEP +void _sys_profiler_enter_sleep(void) +{ + _sys_profiler_sleep_start_time = nano_cycle_get_32(); +} + +void _sys_profiler_exit_sleep(void) +{ + uint32_t data[3]; + + data[0] = nano_tick_get_32(); + data[1] = (nano_cycle_get_32() - _sys_profiler_sleep_start_time) / sys_clock_hw_cycles_per_tick; + /* register the cause of exiting sleep mode */ + data[2] = _sys_current_irq_key_get(); + + sys_profiler_put(PROFILER_SLEEP_EVENT_ID, data, ARRAY_SIZE(data)); +} +#endif /* CONFIG_PROFILER_SLEEP */