Zephyr
Contents
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 . . .
^ Z
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 };