-
Notifications
You must be signed in to change notification settings - Fork 3k
Add optional tracing to sleep manager lock/unlock #6142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0f6b73a
74bdf1c
21e5f11
5a4027b
bd23625
076548a
fed5115
206cc29
d6f57bc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,18 +14,140 @@ | |
* 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 "mbed_debug.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 MBED_SLEEP_TRACING_ENABLED | ||
|
||
// Length of the identifier extracted from the driver name to store for logging. | ||
#define IDENTIFIER_WIDTH 15 | ||
// Number of drivers that can be stored in the structure | ||
#define STATISTIC_COUNT 10 | ||
|
||
typedef struct 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 sleep_statistic_t* sleep_tracker_find(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 &sleep_stats[i]; | ||
} | ||
} | ||
|
||
return NULL; | ||
} | ||
|
||
static sleep_statistic_t* sleep_tracker_add(const char* const filename) | ||
{ | ||
char temp[IDENTIFIER_WIDTH]; | ||
strncpy(temp, filename, IDENTIFIER_WIDTH); | ||
temp[IDENTIFIER_WIDTH - 1] = '\0'; | ||
|
||
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 &sleep_stats[i]; | ||
} | ||
} | ||
|
||
debug("No free indexes left to use in mbed sleep tracker.\r\n"); | ||
|
||
return NULL; | ||
} | ||
|
||
static void sleep_tracker_print_stats(void) | ||
{ | ||
debug("Sleep locks held:\r\n"); | ||
for (int i = 0; i < STATISTIC_COUNT; ++i) { | ||
if (sleep_stats[i].count == 0) { | ||
continue; | ||
} | ||
|
||
if (sleep_stats[i].identifier[0] == '\0') { | ||
return; | ||
} | ||
|
||
debug("[id: %s, count: %u]\r\n", sleep_stats[i].identifier, | ||
sleep_stats[i].count); | ||
} | ||
} | ||
|
||
void sleep_tracker_lock(const char* const filename, int line) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @scartmell-arm - Is it possible to modify this function to return the index of the entry in sleep_stats? And the unlock caller should pass that back into unlock function, so that we don't have to search for index when in unlock. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like that would require changing the user-facing API, and requiring anyone who uses the sleep tracker to keep track of the index. Currently, the sleep tracing is transparent to the user. I don't think that requiring them to track the index is worth the benefit of not having to look up the index during unlock, especially when this is meant intended primarily as an optional debugging feature. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth adding that sleep tracing is only available in debug mode and just the fact of using it will prevent the board from sleeping, so it's purely development time debug feature. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I dont see in this change set where that would be the case. Can you point me at it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implicitly by using UART. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I dont understand how that is possible given UART is available in develop and release profiles as well. |
||
{ | ||
const char* const stripped_path = strip_path(filename); | ||
|
||
sleep_statistic_t* stat = sleep_tracker_find(stripped_path); | ||
|
||
// Entry for this driver does not exist, create one. | ||
if (stat == NULL) { | ||
stat = sleep_tracker_add(stripped_path); | ||
} | ||
|
||
core_util_atomic_incr_u8(&stat->count, 1); | ||
|
||
debug("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); | ||
sleep_statistic_t* stat = sleep_tracker_find(stripped_path); | ||
|
||
// Entry for this driver does not exist, something went wrong. | ||
if (stat == NULL) { | ||
debug("Unlocking sleep for driver that was not previously locked: %s, ln: %i\r\n", stripped_path, line); | ||
return; | ||
} | ||
|
||
core_util_atomic_decr_u8(&stat->count, 1); | ||
|
||
debug("UNLOCK: %s, ln: %i, lock count: %u\r\n", stripped_path, line, deep_sleep_lock); | ||
} | ||
|
||
#endif // MBED_SLEEP_TRACING_ENABLED | ||
|
||
void sleep_manager_lock_deep_sleep_internal(void) | ||
{ | ||
core_util_critical_section_enter(); | ||
if (deep_sleep_lock == USHRT_MAX) { | ||
|
@@ -36,7 +158,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) { | ||
|
@@ -54,6 +176,9 @@ bool sleep_manager_can_deep_sleep(void) | |
|
||
void sleep_manager_sleep_auto(void) | ||
{ | ||
#ifdef MBED_SLEEP_TRACING_ENABLED | ||
sleep_tracker_print_stats(); | ||
#endif | ||
core_util_critical_section_enter(); | ||
// debug profile should keep debuggers attached, no deep sleep allowed | ||
#ifdef MBED_DEBUG | ||
|
@@ -73,12 +198,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) | ||
{ | ||
|
||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All this runtime processing can be avoided, if we use proper compile time pre-processing macros (
__MODULE__
for ARM and__BASE_FILE__
for GCC_ARM). Not blocking the release, but please update this in next PR.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fine for ARM and GCC, but the only way to do it for IAR seems to be enabling
--no_path_in_file_macros
which seems excessive unless it can be applied selectively to this file.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--no_path_in_file_macros : I guess we will be adding this anyways in future for unified tracing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using filename can we use function name of the caller( the caller will pass
__FUNCTION__
), that will avoid all these processing as well, does that work?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think using
__BASE_FILE__
would work better, it can be added when this is altered to use the tracing.Using
__FUNCTION__
might be problematic. The names of the functions that call lock and unlock are going to be different so tracking which unlock is associated with each lock would be complicated, multiple drivers are also likely to have the same function names that lock/unlock the sleep manager, and it's difficult to identify which driver locked the sleep manager based on the function name alone