mirror of https://github.com/ARMmbed/mbed-os.git
Add optional tracing to sleep manager lock/unlock
Add tracing output to console to track when drivers lock and unlock deep sleep. Tracing output is enabled by configuring the 'SLEEP_PROFILING_ENABLED' at compile time. - Wrapped sleep_manager_lock/sleep_manager_unlock in a macro to conditionally call tracing functions when 'SLEEP_PROFILING_ENABLED' is set. - Define a global structure to track driver names and how many locks they hold in the sleep manager.pull/6142/head
parent
9ddb092d43
commit
0f6b73ae0f
|
@ -14,18 +14,123 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mbed_assert.h"
|
||||
#include "mbed_power_mgmt.h"
|
||||
#include "mbed_critical.h"
|
||||
#include "sleep_api.h"
|
||||
#include "mbed_error.h"
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if DEVICE_SLEEP
|
||||
|
||||
// deep sleep locking counter. A target is allowed to deep sleep if counter == 0
|
||||
static uint16_t deep_sleep_lock = 0U;
|
||||
|
||||
void sleep_manager_lock_deep_sleep(void)
|
||||
#ifdef SLEEP_PROFILING_ENABLED
|
||||
|
||||
// Length of the identifier extracted from the driver name to store for logging.
|
||||
#define IDENTIFIER_WIDTH 7
|
||||
// Number of drivers that can be stored in the structure
|
||||
#define STATISTIC_COUNT 10
|
||||
|
||||
typedef struct __PACKED sleep_statistic {
|
||||
char identifier[IDENTIFIER_WIDTH];
|
||||
uint8_t count;
|
||||
} sleep_statistic_t;
|
||||
|
||||
static sleep_statistic_t sleep_stats[STATISTIC_COUNT];
|
||||
|
||||
static const char* strip_path(const char* const filename)
|
||||
{
|
||||
char *output = strrchr(filename, '/');
|
||||
|
||||
if (output != NULL) {
|
||||
return output + 1;
|
||||
}
|
||||
|
||||
output = strrchr(filename, '\\');
|
||||
|
||||
if (output != NULL) {
|
||||
return output + 1;
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
static size_t sleep_tracker_find_index(const char *const filename)
|
||||
{
|
||||
char temp[IDENTIFIER_WIDTH];
|
||||
strncpy(temp, filename, IDENTIFIER_WIDTH);
|
||||
temp[IDENTIFIER_WIDTH - 1] = '\0';
|
||||
|
||||
// Search for the a driver matching the current name and return it's index
|
||||
for (int i = 0; i < STATISTIC_COUNT; ++i) {
|
||||
if (strcmp(sleep_stats[i].identifier, temp) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// If no driver was found currently in the structure, find the first array
|
||||
// index that hasn't been used by a driver and fill it, then return the
|
||||
// index.
|
||||
for (int i = 0; i < STATISTIC_COUNT; ++i) {
|
||||
if (sleep_stats[i].identifier[0] == '\0') {
|
||||
core_util_critical_section_enter();
|
||||
strncpy(sleep_stats[i].identifier, temp, sizeof(temp));
|
||||
core_util_critical_section_exit();
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// Panic if there are no free indexes left to track with
|
||||
MBED_ASSERT(true);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void sleep_tracker_print_stats(void)
|
||||
{
|
||||
for (int i = 0; i < STATISTIC_COUNT; ++i) {
|
||||
if (sleep_stats[i].count == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sleep_stats[i].identifier[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[id: %s, count: %u]\r\n", sleep_stats[i].identifier,
|
||||
sleep_stats[i].count);
|
||||
}
|
||||
}
|
||||
|
||||
void sleep_tracker_lock(const char* const filename, int line)
|
||||
{
|
||||
const char* const stripped_path = strip_path(filename);
|
||||
size_t index = sleep_tracker_find_index(stripped_path);
|
||||
|
||||
core_util_atomic_incr_u8(&sleep_stats[index].count, 1);
|
||||
|
||||
printf("LOCK: %s, ln: %i, lock count: %u\r\n", stripped_path, line, deep_sleep_lock);
|
||||
}
|
||||
|
||||
void sleep_tracker_unlock(const char* const filename, int line)
|
||||
{
|
||||
const char* const stripped_path = strip_path(filename);
|
||||
size_t index = sleep_tracker_find_index(stripped_path);
|
||||
|
||||
core_util_atomic_decr_u8(&sleep_stats[index].count, 1);
|
||||
|
||||
printf("UNLOCK: %s, ln: %i, lock count: %u\r\n", stripped_path, line, deep_sleep_lock);
|
||||
sleep_tracker_print_stats();
|
||||
printf("\r\n");
|
||||
}
|
||||
|
||||
#endif // SLEEP_PROFILING_ENABLED
|
||||
|
||||
void sleep_manager_lock_deep_sleep_internal(void)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
if (deep_sleep_lock == USHRT_MAX) {
|
||||
|
@ -36,7 +141,7 @@ void sleep_manager_lock_deep_sleep(void)
|
|||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void sleep_manager_unlock_deep_sleep(void)
|
||||
void sleep_manager_unlock_deep_sleep_internal(void)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
if (deep_sleep_lock == 0) {
|
||||
|
@ -73,12 +178,12 @@ void sleep_manager_sleep_auto(void)
|
|||
// locking is valid only if DEVICE_SLEEP is defined
|
||||
// we provide empty implementation
|
||||
|
||||
void sleep_manager_lock_deep_sleep(void)
|
||||
void sleep_manager_lock_deep_sleep_internal(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void sleep_manager_unlock_deep_sleep(void)
|
||||
void sleep_manager_unlock_deep_sleep_internal(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#ifndef MBED_POWER_MGMT_H
|
||||
#define MBED_POWER_MGMT_H
|
||||
|
||||
#include "hal/sleep_api.h"
|
||||
#include "sleep_api.h"
|
||||
#include "mbed_toolchain.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
|
@ -63,6 +63,34 @@ extern "C" {
|
|||
* }
|
||||
* @endcode
|
||||
*/
|
||||
#ifdef SLEEP_PROFILING_ENABLED
|
||||
|
||||
#define sleep_manager_lock_deep_sleep() \
|
||||
do \
|
||||
{ \
|
||||
sleep_manager_lock_deep_sleep_internal(); \
|
||||
sleep_tracker_lock(__FILE__, __LINE__); \
|
||||
} while (0);
|
||||
|
||||
#define sleep_manager_unlock_deep_sleep() \
|
||||
do \
|
||||
{ \
|
||||
sleep_manager_unlock_deep_sleep_internal(); \
|
||||
sleep_tracker_unlock(__FILE__, __LINE__); \
|
||||
} while (0);
|
||||
|
||||
void sleep_tracker_lock(const char *const filename, int line);
|
||||
void sleep_tracker_unlock(const char *const filename, int line);
|
||||
|
||||
#else
|
||||
|
||||
#define sleep_manager_lock_deep_sleep() \
|
||||
sleep_manager_lock_deep_sleep_internal()
|
||||
|
||||
#define sleep_manager_unlock_deep_sleep() \
|
||||
sleep_manager_lock_deep_sleep_internal()
|
||||
|
||||
#endif // SLEEP_PROFILING_ENABLED
|
||||
|
||||
/** Lock the deep sleep mode
|
||||
*
|
||||
|
@ -76,7 +104,7 @@ extern "C" {
|
|||
* The lock is a counter, can be locked up to USHRT_MAX
|
||||
* This function is IRQ and thread safe
|
||||
*/
|
||||
void sleep_manager_lock_deep_sleep(void);
|
||||
void sleep_manager_lock_deep_sleep_internal(void);
|
||||
|
||||
/** Unlock the deep sleep mode
|
||||
*
|
||||
|
@ -85,96 +113,13 @@ void sleep_manager_lock_deep_sleep(void);
|
|||
* The lock is a counter, should be equally unlocked as locked
|
||||
* This function is IRQ and thread safe
|
||||
*/
|
||||
void sleep_manager_unlock_deep_sleep(void);
|
||||
void sleep_manager_unlock_deep_sleep_internal(void);
|
||||
|
||||
/** Get the status of deep sleep allowance for a target
|
||||
*
|
||||
* @return true if a target can go to deepsleep, false otherwise
|
||||
*/
|
||||
bool sleep_manager_can_deep_sleep(void);
|
||||
|
||||
/** Enter auto selected sleep mode. It chooses the sleep or deeepsleep modes based
|
||||
* on the deepsleep locking counter
|
||||
*
|
||||
* This function is IRQ and thread safe
|
||||
*
|
||||
* @note
|
||||
* If MBED_DEBUG is defined, only hal_sleep is allowed. This ensures the debugger
|
||||
* to be active for debug modes.
|
||||
*
|
||||
*/
|
||||
void sleep_manager_sleep_auto(void);
|
||||
|
||||
/** Send the microcontroller to sleep
|
||||
*
|
||||
* @note This function can be a noop if not implemented by the platform.
|
||||
* @note This function will be a noop in debug mode (debug build profile when MBED_DEBUG is defined).
|
||||
* @note This function will be a noop while uVisor is in use.
|
||||
* @note This function will be a noop if the following conditions are met:
|
||||
* - The RTOS is present
|
||||
* - The processor turn off the Systick clock during sleep
|
||||
* - The target does not implement tickless mode
|
||||
*
|
||||
* The processor is setup ready for sleep, and sent to sleep using __WFI(). In this mode, the
|
||||
* system clock to the core is stopped until a reset or an interrupt occurs. This eliminates
|
||||
* dynamic power used by the processor, memory systems and buses. The processor, peripheral and
|
||||
* memory state are maintained, and the peripherals continue to work and can generate interrupts.
|
||||
*
|
||||
* The processor can be woken up by any internal peripheral interrupt or external pin interrupt.
|
||||
*
|
||||
* @note
|
||||
* The mbed interface semihosting is disconnected as part of going to sleep, and can not be restored.
|
||||
* Flash re-programming and the USB serial port will remain active, but the mbed program will no longer be
|
||||
* able to access the LocalFileSystem
|
||||
*/
|
||||
static inline void sleep(void)
|
||||
{
|
||||
#if !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED))
|
||||
#if DEVICE_SLEEP
|
||||
#if (MBED_CONF_RTOS_PRESENT == 0) || (DEVICE_STCLK_OFF_DURING_SLEEP == 0) || defined(MBED_TICKLESS)
|
||||
sleep_manager_sleep_auto();
|
||||
#endif /* (MBED_CONF_RTOS_PRESENT == 0) || (DEVICE_STCLK_OFF_DURING_SLEEP == 0) || defined(MBED_TICKLESS) */
|
||||
#endif /* DEVICE_SLEEP */
|
||||
#endif /* !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED)) */
|
||||
}
|
||||
|
||||
/** Send the microcontroller to deep sleep
|
||||
*
|
||||
* @note This function can be a noop if not implemented by the platform.
|
||||
* @note This function will be a noop in debug mode (debug build profile when MBED_DEBUG is defined)
|
||||
* @note This function will be a noop while uVisor is in use.
|
||||
*
|
||||
* This processor is setup ready for deep sleep, and sent to sleep. This mode
|
||||
* has the same sleep features as sleep plus it powers down peripherals and clocks. All state
|
||||
* is still maintained.
|
||||
*
|
||||
* The processor can only be woken up by an external interrupt on a pin or a watchdog timer.
|
||||
*
|
||||
* @note
|
||||
* The mbed interface semihosting is disconnected as part of going to sleep, and can not be restored.
|
||||
* Flash re-programming and the USB serial port will remain active, but the mbed program will no longer be
|
||||
* able to access the LocalFileSystem
|
||||
*/
|
||||
|
||||
MBED_DEPRECATED_SINCE("mbed-os-5.6", "One entry point for an application, use sleep()")
|
||||
static inline void deepsleep(void)
|
||||
{
|
||||
#if !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED))
|
||||
#if DEVICE_SLEEP
|
||||
sleep_manager_sleep_auto();
|
||||
#endif /* DEVICE_SLEEP */
|
||||
#endif /* !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED)) */
|
||||
}
|
||||
|
||||
/** Resets the processor and most of the sub-system
|
||||
*
|
||||
* @note Does not affect the debug sub-system
|
||||
*/
|
||||
static inline void system_reset(void)
|
||||
{
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue