kernel: overhaul unused stack measurement

The existing stack_analyze APIs had some problems:

1. Not properly namespaced
2. Accepted the stack object as a parameter, yet the stack object
   does not contain the necessary information to get the associated
   buffer region, the thread object is needed for this
3. Caused a crash on certain platforms that do not allow inspection
   of unused stack space for the currently running thread
4. No user mode access
5. Separately passed in thread name

We deprecate these functions and add a new API
k_thread_stack_space_get() which addresses all of these issues.

A helper API log_stack_usage() also added which resembles
STACK_ANALYZE() in functionality.

Fixes: #17852

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2020-02-05 10:41:58 -08:00 committed by Johan Hedberg
commit efc5fe07a2
16 changed files with 229 additions and 46 deletions

View file

@ -60,6 +60,7 @@ static inline size_t stack_unused_space_get(const char *stack, size_t size)
return unused;
}
__deprecated
static inline void stack_analyze(const char *name, const char *stack,
unsigned int size)
{
@ -82,11 +83,33 @@ static inline void stack_analyze(const char *name, const char *stack,
* @param name Name of the stack
* @param sym The symbol of the stack
*/
#define STACK_ANALYZE(name, sym) \
#define STACK_ANALYZE(name, sym) DEPRECATED_MACRO \
do { \
stack_analyze(name, \
Z_THREAD_STACK_BUFFER(sym), \
K_THREAD_STACK_SIZEOF(sym)); \
} while (false)
static inline void log_stack_usage(const struct k_thread *thread)
{
#if defined(CONFIG_INIT_STACKS) && defined(CONFIG_THREAD_STACK_INFO)
size_t unused, size = thread->stack_info.size;
LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
if (k_thread_stack_space_get(thread, &unused) == 0) {
unsigned int pcnt = ((size - unused) * 100U) / size;
const char *tname;
tname = k_thread_name_get((k_tid_t)thread);
if (tname == NULL) {
tname = "unknown";
}
LOG_INF("%p (%s):\tunused %zu\tusage %zu / %zu (%u %%)",
thread, tname, unused, size - unused, size,
pcnt);
}
#endif
}
#endif /* ZEPHYR_INCLUDE_DEBUG_STACK_H_ */

View file

@ -834,6 +834,31 @@ static inline void k_thread_resource_pool_assign(struct k_thread *thread,
thread->resource_pool = pool;
}
#if defined(CONFIG_INIT_STACKS) && defined(CONFIG_THREAD_STACK_INFO)
/**
* @brief Obtain stack usage information for the specified thread
*
* User threads will need to have permission on the target thread object.
*
* Some hardware may prevent inspection of a stack buffer currently in use.
* If this API is called from supervisor mode, on the currently running thread,
* on a platform which selects CONFIG_NO_UNUSED_STACK_INSPECTION, an error
* will be generated.
*
* @param thread Thread to inspect stack information
* @param unused_ptr Output parameter, filled in with the unused stack space
* of the target thread in bytes.
* @return 0 on success
* @return -EBADF Bad thread object (user mode only)
* @return -EPERM No permissions on thread object (user mode only)
* #return -ENOTSUP Forbidden by hardware policy
* @return -EINVAL Thread is uninitialized or exited (user mode only)
* @return -EFAULT Bad memory address for unused_ptr (user mode only)
*/
__syscall int k_thread_stack_space_get(const struct k_thread *thread,
size_t *unused_ptr);
#endif
#if (CONFIG_HEAP_MEM_POOL_SIZE > 0)
/**
* @brief Assign the system heap as a thread's resource pool