Zephyr
^ Zephyr RTOS Logger and Backend Features
- https://docs.zephyrproject.org/2.6.0/reference/logging/index.html#logger-backend-interface
- https://docs.zephyrproject.org/2.6.0/reference/logging/index.html#default-frontend
Zephyr's thread_analyzer when not configured to dump reports to printk() instead sends thread data to LOG_INF(). Excerpt from Zephyr file `./zephyr/subsys/debug/thread_analyzer.c`:
11 #include <kernel.h> 12 #include <debug/thread_analyzer.h> 13 #include <debug/stack.h> 14 #include <kernel.h> 15 #include <logging/log.h> 16 #include <stdio.h> 17 18 LOG_MODULE_REGISTER(thread_analyzer, CONFIG_THREAD_ANALYZER_LOG_LEVEL); 19 20 #if IS_ENABLED(CONFIG_THREAD_ANALYZER_USE_PRINTK) 21 #define THREAD_ANALYZER_PRINT(...) printk(__VA_ARGS__) 22 #define THREAD_ANALYZER_FMT(str) str "\n" 23 #define THREAD_ANALYZER_VSTR(str) (str) 24 #else 25 #define THREAD_ANALYZER_PRINT(...) LOG_INF(__VA_ARGS__) 26 #define THREAD_ANALYZER_FMT(str) str 27 #define THREAD_ANALYZER_VSTR(str) log_strdup(str) 28 #endif
Zephyr macro `LOG_INF` is in turn defined:
ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/zephyr$ grep -nr LOG_INF ./* | grep define ./include/logging/log.h:61:#define LOG_INF(...) Z_LOG(LOG_LEVEL_INF, __VA_ARGS__)
Define of Z_LOG:
ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/zephyr$ grep -nr 'Z_LOG[^_]' ./*
./include/logging/log_core.h:295:#define Z_LOG2(_level, _source, _dsource, ...) do { \
./include/logging/log_core.h:329:#define Z_LOG(_level, ...) \
$ grep -nr 'Z_LOG[^_]' ./* $ vi ./include/logging/log_core.h 329 #define Z_LOG(_level, ...) \ 330 Z_LOG2(_level, __log_current_const_data, __log_current_dynamic_data, __VA_ARGS__)
A Zephyr RTOS sample to check out:
`ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/zephyr/samples/subsys/logging/logger$`
^ To Create And To Name Zephyr Threads
^ Zephyr thread_analyzer_cb And Related
Zephyr 2.6.0's thread_analyzer_cb() routine gathers and populates a structure with all pertinent, reported run-time thread statistics. This is however a static routine so we cannot call it directly. Nor does it return the summary thread resource use data to its direct calling routine. There is yet hope, and to understand a path forward here excerpted is the definition of this important thread reporting routine from file `./zephyr/subsys/debug/thread_analyzer.c`:
59 static void thread_analyze_cb(const struct k_thread *cthread, void *user_data)
60 {
61 struct k_thread *thread = (struct k_thread *)cthread;
62 #ifdef CONFIG_THREAD_RUNTIME_STATS
63 k_thread_runtime_stats_t rt_stats_all;
64 k_thread_runtime_stats_t rt_stats_thread;
65 int ret;
66 #endif
67 size_t size = thread->stack_info.size;
68 thread_analyzer_cb cb = user_data;
69 struct thread_analyzer_info info;
70 char hexname[PTR_STR_MAXLEN + 1];
71 const char *name;
72 size_t unused;
73 int err;
74
75
76
77 name = k_thread_name_get((k_tid_t)thread);
78 if (!name || name[0] == '\0') {
79 name = hexname;
80 snprintk(hexname, sizeof(hexname), "%p", (void *)thread);
81 }
82
83 err = k_thread_stack_space_get(thread, &unused);
84 if (err) {
85 THREAD_ANALYZER_PRINT(
86 THREAD_ANALYZER_FMT(
87 " %-20s: unable to get stack space (%d)"),
88 name, err);
88 name, err);
89
90 unused = 0;
91 }
92
93 info.name = name;
94 info.stack_size = size;
95 info.stack_used = size - unused;
96
97 #ifdef CONFIG_THREAD_RUNTIME_STATS
98 ret = 0;
99
100 if (k_thread_runtime_stats_get(thread, &rt_stats_thread) != 0) {
101 ret++;
102 }
103
104 if (k_thread_runtime_stats_all_get(&rt_stats_all) != 0) {
105 ret++;
106 }
107 if (ret == 0) {
108 info.utilization = (rt_stats_thread.execution_cycles * 100U) /
109 rt_stats_all.execution_cycles;
110 }
111 #endif
112 cb(&info);
113 }
The routine which calls this is:
115 void thread_analyzer_run(thread_analyzer_cb cb)
116 {
117 if (IS_ENABLED(CONFIG_THREAD_ANALYZER_RUN_UNLOCKED)) {
118 k_thread_foreach_unlocked(thread_analyze_cb, cb);
119 } else {
120 k_thread_foreach(thread_analyze_cb, cb);
121 }
122 }
We should be able to directly call thread_analyzer_run(thread_analyzer_cb cb). If yes, and if we can learn how &info is defined, we should be able to redirect thread_analyzer reports to an arbitrary UART . . .
^ struct thread_analyzer_info
ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/zephyr$ grep -nr 'struct thread_analyzer_info' ./*
./include/debug/thread_analyzer.h:23:struct thread_analyzer_info {
./include/debug/thread_analyzer.h:44:typedef void (*thread_analyzer_cb)(struct thread_analyzer_info *info);
Structure definition for &info passed to thread_analyzer_cb() function above:
/** @defgroup thread_analyzer Thread analyzer
* @brief Module for analyzing threads
*
* This module implements functions and the configuration that simplifies
* thread analysis.
* @{
*/
struct thread_analyzer_info {
/** The name of the thread or stringified address of the thread handle
* if name is not set.
*/
const char *name;
/** The total size of the stack*/
size_t stack_size;
/** Stack size in used */
size_t stack_used;
#ifdef CONFIG_THREAD_RUNTIME_STATS
unsigned int utilization;
#endif
};
----- ----- ----- ----- ----- ----- ----- ----- -----
Zephyr Memory Management
^ Zephyr Kernel Timing
Following link at Zephyr Project documentation pages has valuable info on various Zephyr timing and work queueing facilities:
-
Similar documentation but describes sources of timing inaccuracies in running Zephyr RTOS relative to civil, real world time:
Must #include <kernel.h> . . .
Related:
Important to follow up on this bug report relating to above mentioned Zephyr timing features: