debug: analyzer: add support for thread runtime stats

Add thread runtime statistics to the thread analyser.

With CONFIG_THREAD_RUNTIME_STATS enabled:

Booting from ROM..*** Booting Zephyr OS build zephyr-v2.4.0-2330-g77be0e93e65b  ***
thread_a: Hello World from cpu 0 on qemu_x86!
Thread analyze:
 thread_b            : STACK: unused 740 usage 284 / 1024 (27 %); CPU: 0 %
 thread_analyzer     : STACK: unused 8 usage 504 / 512 (98 %); CPU: 0 %
 thread_a            : STACK: unused 648 usage 376 / 1024 (36 %); CPU: 98 %
 idle 00             : STACK: unused 204 usage 116 / 320 (36 %); CPU: 0 %
thread_b: Hello World from cpu 0 on qemu_x86!
thread_a: Hello World from cpu 0 on qemu_x86!
thread_b: Hello World from cpu 0 on qemu_x86!
thread_a: Hello World from cpu 0 on qemu_x86!
thread_b: Hello World from cpu 0 on qemu_x86!
thread_a: Hello World from cpu 0 on qemu_x86!
thread_b: Hello World from cpu 0 on qemu_x86!
thread_a: Hello World from cpu 0 on qemu_x86!
Thread analyze:
 thread_b            : STACK: unused 648 usage 376 / 1024 (36 %); CPU: 7 %
 thread_analyzer     : STACK: unused 8 usage 504 / 512 (98 %); CPU: 0 %
 thread_a            : STACK: unused 648 usage 376 / 1024 (36 %); CPU: 9 %
 idle 00             : STACK: unused 204 usage 116 / 320 (36 %); CPU: 82 %
thread_b: Hello World from cpu 0 on qemu_x86!

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
Anas Nashif 2020-12-12 08:41:27 -05:00
parent 7009012d67
commit 802d214582
4 changed files with 39 additions and 1 deletions

View file

@ -29,6 +29,10 @@ struct thread_analyzer_info {
size_t stack_size; size_t stack_size;
/** Stack size in used */ /** Stack size in used */
size_t stack_used; size_t stack_used;
#ifdef CONFIG_THREAD_RUNTIME_STATS
unsigned int utilization;
#endif
}; };
/** @brief Thread analyzer stack size callback function /** @brief Thread analyzer stack size callback function

View file

@ -60,6 +60,7 @@ void helloLoop(const char *my_name,
} }
/* wait a while, then let other thread have a turn */ /* wait a while, then let other thread have a turn */
k_busy_wait(100000);
k_msleep(SLEEPTIME); k_msleep(SLEEPTIME);
k_sem_give(other_sem); k_sem_give(other_sem);
} }

View file

@ -17,6 +17,7 @@ menuconfig THREAD_ANALYZER
select INIT_STACKS select INIT_STACKS
select THREAD_MONITOR select THREAD_MONITOR
select THREAD_STACK_INFO select THREAD_STACK_INFO
select THREAD_RUNTIME_STATS
help help
Enable thread analyzer functionality and all the required modules. Enable thread analyzer functionality and all the required modules.
This module may be used to debug thread configuration issues, e.g. This module may be used to debug thread configuration issues, e.g.

View file

@ -38,18 +38,32 @@ LOG_MODULE_REGISTER(thread_analyzer, CONFIG_THREAD_ANALYZER_LOG_LEVEL);
static void thread_print_cb(struct thread_analyzer_info *info) static void thread_print_cb(struct thread_analyzer_info *info)
{ {
unsigned int pcnt = (info->stack_used * 100U) / info->stack_size; unsigned int pcnt = (info->stack_used * 100U) / info->stack_size;
#ifdef CONFIG_THREAD_RUNTIME_STATS
THREAD_ANALYZER_PRINT(
THREAD_ANALYZER_FMT(
" %-20s: STACK: unused %zu usage %zu / %zu (%zu %%); CPU: %zu %%"),
THREAD_ANALYZER_VSTR(info->name),
info->stack_size - info->stack_used, info->stack_used,
info->stack_size, pcnt,
info->utilization);
#else
THREAD_ANALYZER_PRINT( THREAD_ANALYZER_PRINT(
THREAD_ANALYZER_FMT( THREAD_ANALYZER_FMT(
" %-20s: unused %zu usage %zu / %zu (%zu %%)"), " %-20s: unused %zu usage %zu / %zu (%zu %%)"),
THREAD_ANALYZER_VSTR(info->name), THREAD_ANALYZER_VSTR(info->name),
info->stack_size - info->stack_used, info->stack_used, info->stack_size - info->stack_used, info->stack_used,
info->stack_size, pcnt); info->stack_size, pcnt);
#endif
} }
static void thread_analyze_cb(const struct k_thread *cthread, void *user_data) static void thread_analyze_cb(const struct k_thread *cthread, void *user_data)
{ {
struct k_thread *thread = (struct k_thread *)cthread; struct k_thread *thread = (struct k_thread *)cthread;
#ifdef CONFIG_THREAD_RUNTIME_STATS
k_thread_runtime_stats_t rt_stats_all;
k_thread_runtime_stats_t rt_stats_thread;
int ret;
#endif
size_t size = thread->stack_info.size; size_t size = thread->stack_info.size;
thread_analyzer_cb cb = user_data; thread_analyzer_cb cb = user_data;
struct thread_analyzer_info info; struct thread_analyzer_info info;
@ -58,6 +72,8 @@ static void thread_analyze_cb(const struct k_thread *cthread, void *user_data)
size_t unused; size_t unused;
int err; int err;
name = k_thread_name_get((k_tid_t)thread); name = k_thread_name_get((k_tid_t)thread);
if (!name || name[0] == '\0') { if (!name || name[0] == '\0') {
name = hexname; name = hexname;
@ -77,6 +93,22 @@ static void thread_analyze_cb(const struct k_thread *cthread, void *user_data)
info.name = name; info.name = name;
info.stack_size = size; info.stack_size = size;
info.stack_used = size - unused; info.stack_used = size - unused;
#ifdef CONFIG_THREAD_RUNTIME_STATS
ret = 0;
if (k_thread_runtime_stats_get(thread, &rt_stats_thread) != 0) {
ret++;
};
if (k_thread_runtime_stats_all_get(&rt_stats_all) != 0) {
ret++;
}
if (ret == 0) {
info.utilization = (rt_stats_thread.execution_cycles * 100U) /
rt_stats_all.execution_cycles;
}
#endif
cb(&info); cb(&info);
} }