Difference between revisions of "Zephyr"

From Wiki at Neela Nurseries
Jump to: navigation, search
m (Zephyr macro to create thread, Zephyr API routine to give existing thread a name.)
m
Line 68: Line 68:
  
 
*  https://docs.zephyrproject.org/latest/reference/kernel/threads/index.html?highlight=k_thread_create#c.k_thread_name_set
 
*  https://docs.zephyrproject.org/latest/reference/kernel/threads/index.html?highlight=k_thread_create#c.k_thread_name_set
 +
 +
<!-- comentario -->
 +
 +
== [[#top|^]] 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`:
 +
 +
<pre>
 +
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 }
 +
</pre>
 +
 +
The routine which calls this is:
 +
 +
<pre>
 +
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 }
 +
</pre>
 +
 +
We should be able to directly call <code>thread_analyzer_run(thread_analyzer_cb cb)</code>.  If yes, and if we can learn how &info is defined, we should be able to redirect thread_analyzer reports to an arbitrary UART . . .
  
 
<!-- comentario -->
 
<!-- comentario -->

Revision as of 06:51, 13 November 2021

Zephyr RTOS Logger and Backend Features

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 . . .