Skip to content

Commit 0f6b73a

Browse files
author
Steven Cartmell
committed
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.
1 parent 9ddb092 commit 0f6b73a

File tree

2 files changed

+140
-90
lines changed

2 files changed

+140
-90
lines changed

hal/mbed_sleep_manager.c

Lines changed: 109 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,123 @@
1414
* limitations under the License.
1515
*/
1616

17+
#include "mbed_assert.h"
1718
#include "mbed_power_mgmt.h"
1819
#include "mbed_critical.h"
1920
#include "sleep_api.h"
2021
#include "mbed_error.h"
2122
#include <limits.h>
23+
#include <stdio.h>
2224

2325
#if DEVICE_SLEEP
2426

2527
// deep sleep locking counter. A target is allowed to deep sleep if counter == 0
2628
static uint16_t deep_sleep_lock = 0U;
2729

28-
void sleep_manager_lock_deep_sleep(void)
30+
#ifdef SLEEP_PROFILING_ENABLED
31+
32+
// Length of the identifier extracted from the driver name to store for logging.
33+
#define IDENTIFIER_WIDTH 7
34+
// Number of drivers that can be stored in the structure
35+
#define STATISTIC_COUNT 10
36+
37+
typedef struct __PACKED sleep_statistic {
38+
char identifier[IDENTIFIER_WIDTH];
39+
uint8_t count;
40+
} sleep_statistic_t;
41+
42+
static sleep_statistic_t sleep_stats[STATISTIC_COUNT];
43+
44+
static const char* strip_path(const char* const filename)
45+
{
46+
char *output = strrchr(filename, '/');
47+
48+
if (output != NULL) {
49+
return output + 1;
50+
}
51+
52+
output = strrchr(filename, '\\');
53+
54+
if (output != NULL) {
55+
return output + 1;
56+
}
57+
58+
return filename;
59+
}
60+
61+
static size_t sleep_tracker_find_index(const char *const filename)
62+
{
63+
char temp[IDENTIFIER_WIDTH];
64+
strncpy(temp, filename, IDENTIFIER_WIDTH);
65+
temp[IDENTIFIER_WIDTH - 1] = '\0';
66+
67+
// Search for the a driver matching the current name and return it's index
68+
for (int i = 0; i < STATISTIC_COUNT; ++i) {
69+
if (strcmp(sleep_stats[i].identifier, temp) == 0) {
70+
return i;
71+
}
72+
}
73+
74+
// If no driver was found currently in the structure, find the first array
75+
// index that hasn't been used by a driver and fill it, then return the
76+
// index.
77+
for (int i = 0; i < STATISTIC_COUNT; ++i) {
78+
if (sleep_stats[i].identifier[0] == '\0') {
79+
core_util_critical_section_enter();
80+
strncpy(sleep_stats[i].identifier, temp, sizeof(temp));
81+
core_util_critical_section_exit();
82+
83+
return i;
84+
}
85+
}
86+
87+
// Panic if there are no free indexes left to track with
88+
MBED_ASSERT(true);
89+
90+
return -1;
91+
}
92+
93+
static void sleep_tracker_print_stats(void)
94+
{
95+
for (int i = 0; i < STATISTIC_COUNT; ++i) {
96+
if (sleep_stats[i].count == 0) {
97+
continue;
98+
}
99+
100+
if (sleep_stats[i].identifier[0] == '\0') {
101+
return;
102+
}
103+
104+
printf("[id: %s, count: %u]\r\n", sleep_stats[i].identifier,
105+
sleep_stats[i].count);
106+
}
107+
}
108+
109+
void sleep_tracker_lock(const char* const filename, int line)
110+
{
111+
const char* const stripped_path = strip_path(filename);
112+
size_t index = sleep_tracker_find_index(stripped_path);
113+
114+
core_util_atomic_incr_u8(&sleep_stats[index].count, 1);
115+
116+
printf("LOCK: %s, ln: %i, lock count: %u\r\n", stripped_path, line, deep_sleep_lock);
117+
}
118+
119+
void sleep_tracker_unlock(const char* const filename, int line)
120+
{
121+
const char* const stripped_path = strip_path(filename);
122+
size_t index = sleep_tracker_find_index(stripped_path);
123+
124+
core_util_atomic_decr_u8(&sleep_stats[index].count, 1);
125+
126+
printf("UNLOCK: %s, ln: %i, lock count: %u\r\n", stripped_path, line, deep_sleep_lock);
127+
sleep_tracker_print_stats();
128+
printf("\r\n");
129+
}
130+
131+
#endif // SLEEP_PROFILING_ENABLED
132+
133+
void sleep_manager_lock_deep_sleep_internal(void)
29134
{
30135
core_util_critical_section_enter();
31136
if (deep_sleep_lock == USHRT_MAX) {
@@ -36,7 +141,7 @@ void sleep_manager_lock_deep_sleep(void)
36141
core_util_critical_section_exit();
37142
}
38143

39-
void sleep_manager_unlock_deep_sleep(void)
144+
void sleep_manager_unlock_deep_sleep_internal(void)
40145
{
41146
core_util_critical_section_enter();
42147
if (deep_sleep_lock == 0) {
@@ -73,12 +178,12 @@ void sleep_manager_sleep_auto(void)
73178
// locking is valid only if DEVICE_SLEEP is defined
74179
// we provide empty implementation
75180

76-
void sleep_manager_lock_deep_sleep(void)
181+
void sleep_manager_lock_deep_sleep_internal(void)
77182
{
78183

79184
}
80185

81-
void sleep_manager_unlock_deep_sleep(void)
186+
void sleep_manager_unlock_deep_sleep_internal(void)
82187
{
83188

84189
}

platform/mbed_power_mgmt.h

Lines changed: 31 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#ifndef MBED_POWER_MGMT_H
2424
#define MBED_POWER_MGMT_H
2525

26-
#include "hal/sleep_api.h"
26+
#include "sleep_api.h"
2727
#include "mbed_toolchain.h"
2828
#include <stdbool.h>
2929

@@ -63,6 +63,34 @@ extern "C" {
6363
* }
6464
* @endcode
6565
*/
66+
#ifdef SLEEP_PROFILING_ENABLED
67+
68+
#define sleep_manager_lock_deep_sleep() \
69+
do \
70+
{ \
71+
sleep_manager_lock_deep_sleep_internal(); \
72+
sleep_tracker_lock(__FILE__, __LINE__); \
73+
} while (0);
74+
75+
#define sleep_manager_unlock_deep_sleep() \
76+
do \
77+
{ \
78+
sleep_manager_unlock_deep_sleep_internal(); \
79+
sleep_tracker_unlock(__FILE__, __LINE__); \
80+
} while (0);
81+
82+
void sleep_tracker_lock(const char *const filename, int line);
83+
void sleep_tracker_unlock(const char *const filename, int line);
84+
85+
#else
86+
87+
#define sleep_manager_lock_deep_sleep() \
88+
sleep_manager_lock_deep_sleep_internal()
89+
90+
#define sleep_manager_unlock_deep_sleep() \
91+
sleep_manager_lock_deep_sleep_internal()
92+
93+
#endif // SLEEP_PROFILING_ENABLED
6694

6795
/** Lock the deep sleep mode
6896
*
@@ -76,7 +104,7 @@ extern "C" {
76104
* The lock is a counter, can be locked up to USHRT_MAX
77105
* This function is IRQ and thread safe
78106
*/
79-
void sleep_manager_lock_deep_sleep(void);
107+
void sleep_manager_lock_deep_sleep_internal(void);
80108

81109
/** Unlock the deep sleep mode
82110
*
@@ -85,96 +113,13 @@ void sleep_manager_lock_deep_sleep(void);
85113
* The lock is a counter, should be equally unlocked as locked
86114
* This function is IRQ and thread safe
87115
*/
88-
void sleep_manager_unlock_deep_sleep(void);
116+
void sleep_manager_unlock_deep_sleep_internal(void);
89117

90118
/** Get the status of deep sleep allowance for a target
91119
*
92120
* @return true if a target can go to deepsleep, false otherwise
93121
*/
94122
bool sleep_manager_can_deep_sleep(void);
95-
96-
/** Enter auto selected sleep mode. It chooses the sleep or deeepsleep modes based
97-
* on the deepsleep locking counter
98-
*
99-
* This function is IRQ and thread safe
100-
*
101-
* @note
102-
* If MBED_DEBUG is defined, only hal_sleep is allowed. This ensures the debugger
103-
* to be active for debug modes.
104-
*
105-
*/
106-
void sleep_manager_sleep_auto(void);
107-
108-
/** Send the microcontroller to sleep
109-
*
110-
* @note This function can be a noop if not implemented by the platform.
111-
* @note This function will be a noop in debug mode (debug build profile when MBED_DEBUG is defined).
112-
* @note This function will be a noop while uVisor is in use.
113-
* @note This function will be a noop if the following conditions are met:
114-
* - The RTOS is present
115-
* - The processor turn off the Systick clock during sleep
116-
* - The target does not implement tickless mode
117-
*
118-
* The processor is setup ready for sleep, and sent to sleep using __WFI(). In this mode, the
119-
* system clock to the core is stopped until a reset or an interrupt occurs. This eliminates
120-
* dynamic power used by the processor, memory systems and buses. The processor, peripheral and
121-
* memory state are maintained, and the peripherals continue to work and can generate interrupts.
122-
*
123-
* The processor can be woken up by any internal peripheral interrupt or external pin interrupt.
124-
*
125-
* @note
126-
* The mbed interface semihosting is disconnected as part of going to sleep, and can not be restored.
127-
* Flash re-programming and the USB serial port will remain active, but the mbed program will no longer be
128-
* able to access the LocalFileSystem
129-
*/
130-
static inline void sleep(void)
131-
{
132-
#if !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED))
133-
#if DEVICE_SLEEP
134-
#if (MBED_CONF_RTOS_PRESENT == 0) || (DEVICE_STCLK_OFF_DURING_SLEEP == 0) || defined(MBED_TICKLESS)
135-
sleep_manager_sleep_auto();
136-
#endif /* (MBED_CONF_RTOS_PRESENT == 0) || (DEVICE_STCLK_OFF_DURING_SLEEP == 0) || defined(MBED_TICKLESS) */
137-
#endif /* DEVICE_SLEEP */
138-
#endif /* !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED)) */
139-
}
140-
141-
/** Send the microcontroller to deep sleep
142-
*
143-
* @note This function can be a noop if not implemented by the platform.
144-
* @note This function will be a noop in debug mode (debug build profile when MBED_DEBUG is defined)
145-
* @note This function will be a noop while uVisor is in use.
146-
*
147-
* This processor is setup ready for deep sleep, and sent to sleep. This mode
148-
* has the same sleep features as sleep plus it powers down peripherals and clocks. All state
149-
* is still maintained.
150-
*
151-
* The processor can only be woken up by an external interrupt on a pin or a watchdog timer.
152-
*
153-
* @note
154-
* The mbed interface semihosting is disconnected as part of going to sleep, and can not be restored.
155-
* Flash re-programming and the USB serial port will remain active, but the mbed program will no longer be
156-
* able to access the LocalFileSystem
157-
*/
158-
159-
MBED_DEPRECATED_SINCE("mbed-os-5.6", "One entry point for an application, use sleep()")
160-
static inline void deepsleep(void)
161-
{
162-
#if !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED))
163-
#if DEVICE_SLEEP
164-
sleep_manager_sleep_auto();
165-
#endif /* DEVICE_SLEEP */
166-
#endif /* !(defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED)) */
167-
}
168-
169-
/** Resets the processor and most of the sub-system
170-
*
171-
* @note Does not affect the debug sub-system
172-
*/
173-
static inline void system_reset(void)
174-
{
175-
NVIC_SystemReset();
176-
}
177-
178123
#ifdef __cplusplus
179124
}
180125
#endif

0 commit comments

Comments
 (0)