-
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 1 commit
0f6b73a
74bdf1c
21e5f11
5a4027b
bd23625
076548a
fed5115
206cc29
d6f57bc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
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.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
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. All this runtime processing can be avoided, if we use proper compile time pre-processing macros ( 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. That's fine for ARM and GCC, but the only way to do it for IAR seems to be enabling 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. --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 commentThe 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 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 think using Using |
||
{ | ||
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) | ||
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); | ||
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); | ||
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. Why is this printf and not debug? If debug it could be stripped from a release build. |
||
} | ||
|
||
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); | ||
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 - sleep_tracker_find_index functions adds the filename to sleep_stats if the entry is not found. Why should we add a new entry in unlock call? As of now, if somebody calls unlock without adding lock first we will still add the entry. Is that expected? 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 can be changed, though it's unlikely to cause problems at the moment. I could separate out the find and add code. If a driver is unlocking sleep manager without first locking it 's going to cause an error() eventually via the unlock code which checks for underflows. 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. Please make that change, if somebody tried to call unlock without locking it should be treated as an error. We should not add a new entry and go with it which might cause inadvertent behaviors. |
||
|
||
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); | ||
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. Why is this printf and not debug? If debug it could be stripped from a release build. |
||
sleep_tracker_print_stats(); | ||
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 think its an overkill to print the stats on every unlock call, particularly when we are printing the LOCK/UNLOCK info in the sleep_tracker_lock/unlock calls. But, I'm not going to block this PR for that as its not a major blocker, but you may want to re-think on that. |
||
printf("\r\n"); | ||
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. Please move this printf inside sleep_tracker_print_stats, makes it look cleaner. |
||
} | ||
|
||
#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) | ||
{ | ||
|
||
} | ||
|
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.
Remove the
__PACKED
it doesn't make any difference here and generally I'm sceptical about use of packed structures, it may have negative effects on performance and put pressure on the bus with unaligned accesses.