Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
rtos_mon_arch.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2016 Gautier Hattenberger <gautier.hattenberger@enac.fr>
3 * 2020 Gautier Hattenberger, Alexandre Bustico
4 *
5 * This file is part of paparazzi
6 *
7 * paparazzi is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * paparazzi is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with paparazzi; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 */
30#include <ch.h>
31
32#if !CH_DBG_STATISTICS
33#error CH_DBG_STATISTICS should be defined to TRUE to use this monitoring tool
34#endif
35
45
47
48static uint16_t get_stack_free(const thread_t *tp);
52
53#if USE_SHELL
54#include "modules/core/shell.h"
55#include "mcu_periph/sys_time.h"
56#include "printf.h"
57#include "string.h"
58
59typedef struct _ThreadCpuInfo {
61 float cpu[RTOS_MON_MAX_THREADS];
62 float totalTicks;
63 float totalISRTicks;
65
66
68{
69 const thread_t *tp = chRegFirstThread();
70 uint32_t idx = 0;
71
72 ti->totalTicks = 0;
73 do {
74 ti->ticks[idx] = (float) tp->stats.cumulative;
75 ti->totalTicks += ti->ticks[idx];
77 idx++;
78 } while ((tp != NULL) && (idx < RTOS_MON_MAX_THREADS));
79 ti->totalISRTicks = currcore->kernel_stats.m_crit_isr.cumulative;
80 ti->totalTicks += ti->totalISRTicks;
82 idx = 0;
83 do {
84 ti->cpu[idx] = (ti->totalTicks > 0.f) ? ((ti->ticks[idx] * 100.f) / ti->totalTicks) : 0.f;
86 idx++;
87 } while ((tp != NULL) && (idx < RTOS_MON_MAX_THREADS));
88}
89
90static float stampThreadGetCpuPercent(const ThreadCpuInfo *ti, const uint32_t idx)
91{
93 return -1.f;
94 }
95
96 return ti->cpu[idx];
97}
98
99static float stampISRGetCpuPercent(const ThreadCpuInfo *ti)
100{
101 return (ti->totalTicks > 0.f) ? (ti->totalISRTicks * 100.0f / ti->totalTicks) : 0.f;
102}
103
104static void cmd_threads(BaseSequentialStream *lchp, int argc, const char *const argv[])
105{
106 static const char *states[] = {CH_STATE_NAMES};
108 (void)argv;
109 (void)argc;
110 float totalTicks = 0;
111 float idleTicks = 0;
112
114 .ticks = {[0 ... RTOS_MON_MAX_THREADS - 1] = 0.f},
115 .cpu = {[0 ... RTOS_MON_MAX_THREADS - 1] = -1.f},
116 .totalTicks = 0.f,
117 .totalISRTicks = 0.f
118 };
119
121
122 chprintf(lchp, " addr stack frestk prio refs state time \t percent name\r\n");
123 uint32_t idx = 0;
124 do {
125 chprintf(lchp, "%.8lx %.8lx %6lu %4lu %4lu %9s %9lu %.2f%% \t%s\r\n",
126 (uint32_t)tp, (uint32_t)tp->ctx.sp,
128 (uint32_t)tp->hdr.pqueue.prio, (uint32_t)(tp->refs - 1),
129 states[tp->state],
130 (uint32_t)RTC2MS(STM32_SYSCLK, tp->stats.cumulative),
133
134 totalTicks += (float)tp->stats.cumulative;
135 if (strcmp(chRegGetThreadNameX(tp), "idle") == 0) {
136 idleTicks = (float)tp->stats.cumulative;
137 }
139 idx++;
140 } while (tp != NULL);
141
142 totalTicks += currcore->kernel_stats.m_crit_isr.cumulative;
143 const float idlePercent = (totalTicks > 0.f) ? ((idleTicks * 100.f) / totalTicks) : 0.f;
144 const float cpuPercent = 100.f - idlePercent;
145 chprintf(lchp, "Interrupt Service Routine \t\t %9lu %.2f%% \tISR\r\n",
146 (uint32_t)RTC2MS(STM32_SYSCLK, threadCpuInfo.totalISRTicks),
148 chprintf(lchp, "\r\ncpu load = %.2f%%\r\n", cpuPercent);
149}
150
151static void cmd_rtos_mon(shell_stream_t *sh, int argc, const char *const argv[])
152{
153 (void) argv;
154 if (argc > 0) {
155 chprintf(sh, "Usage: rtos_mon\r\n");
156 return;
157 }
158
159 chprintf(sh, "Data reported in the RTOS_MON message:\r\n");
160 chprintf(sh, " core free mem: %u\r\n", rtos_mon.core_free_memory);
161 chprintf(sh, " heap free mem: %u\r\n", rtos_mon.heap_free_memory);
162 chprintf(sh, " heap fragments: %u\r\n", rtos_mon.heap_fragments);
163 chprintf(sh, " heap largest: %u\r\n", rtos_mon.heap_largest);
164 chprintf(sh, " CPU load: %d \%\r\n", rtos_mon.cpu_load);
165 chprintf(sh, " number of threads: %d\r\n", rtos_mon.thread_counter);
166 chprintf(sh, " thread names: %s\r\n", rtos_mon.thread_names);
167 for (int i = 0; i < rtos_mon.thread_counter; i++) {
168 chprintf(sh, " thread %d load: %0.1f, free stack: %d\r\n", i,
169 (float)rtos_mon.thread_load[i] / 10.f, rtos_mon.thread_free_stack[i]);
170 }
171 chprintf(sh, " CPU time: %.2f\r\n", rtos_mon.cpu_time);
172}
173#endif
174
176{
177#if USE_SHELL
178 shell_add_entry("rtos_mon", cmd_rtos_mon);
179 shell_add_entry("threads", cmd_threads);
180#endif
181}
182
183// Fill data structure
185{
186 int i;
189
195
196 // loop threads to find idle thread
197 // store info on other threads
198 thread_t *tp;
200 rttime_t sum = 0;
201 rttime_t isr_time = currcore->kernel_stats.m_crit_isr.cumulative;
204 do {
205 const char *name = chRegGetThreadNameX(tp);
206 if (name == NULL) {
207 name = "";
208 }
209
210 // add beginning of thread name to buffer
211 for (i = 0; i < RTOS_MON_NAME_LEN - 1 && name[i] != '\0'; i++) {
213 }
215
216 // store free stack for this thread
218
219 // store cumulative time spent in thread
220 cpu_window.thread_time[rtos_mon.thread_counter] = tp->stats.cumulative;
222 sum += thread_delta;
223
224 // if current thread is the idle thread, store its sampled value separately
225 if (tp == chSysGetIdleThreadX()) {
227 }
228 // get next thread
231 // increment thread counter
235
236 // sum the time spent in ISR
238 sum += isr_delta;
239
240 // store individual thread load (as deci-percent integer, i.e. 10 * %)
241 for (i = 0; i < rtos_mon.thread_counter; i ++) {
246 }
247
252}
253
255{
256 int32_t index = 0;
257 extern const uint8_t __ram0_end__;
258 unsigned long long *stkAdr = (unsigned long long *)((uint8_t *) tp->wabase);
259 while ((stkAdr[index] == 0x5555555555555555) && (((uint8_t *) & (stkAdr[index])) < &__ram0_end__)) {
260 index++;
261 }
262 const int32_t freeBytes = index * (int32_t) sizeof(long long);
263 return (uint16_t)freeBytes;
264}
265
267{
268 // Return the sampled runtime accumulated by a thread since the previous
269 // monitoring pass. New threads report zero until they exist in both samples.
271 return 0;
272 }
273
274 for (uint8_t i = 0; i < cpu_window.prev_thread_count; i++) {
275 if (cpu_window.prev_thread_ref[i] == tp) {
277 }
278 }
279
280 return 0;
281}
282
284{
285 // Convert a thread runtime delta into deci-percent of the total sampled
286 // runtime window so the result fits the telemetry representation.
287 if (total_ticks == 0) {
288 return 0;
289 }
290
291 return (uint16_t)((1000ULL * (uint64_t)thread_ticks) / (uint64_t)total_ticks);
292}
293
295{
296 // Compute global CPU load over the sampled window from the non-idle share
297 // of the measured runtime, including ISR time in the total budget.
298 if (total_ticks == 0) {
299 return 0;
300 }
301
302 return (uint8_t)((100ULL * (uint64_t)(total_ticks - idle_ticks)) / (uint64_t)total_ticks);
303}
void rtos_mon_periodic_arch(void)
void rtos_mon_init_arch(void)
static uint16_t get_thread_load_x10(rttime_t thread_ticks, rttime_t total_ticks)
thread_t * thread_ref[RTOS_MON_MAX_THREADS]
Current thread identities for matching samples.
static uint8_t get_cpu_load_percent(rttime_t idle_ticks, rttime_t total_ticks)
static uint16_t get_stack_free(const thread_t *tp)
thread_t * prev_thread_ref[RTOS_MON_MAX_THREADS]
Previous thread identities for delta lookup.
static rttime_t get_thread_delta(const thread_t *tp, rttime_t current_time)
rttime_t thread_time[RTOS_MON_MAX_THREADS]
Current cumulative thread counters.
uint8_t prev_stats_valid
True after the first full sampling pass.
uint8_t prev_thread_count
Number of valid entries in previous arrays.
static struct rtos_mon_cpu_window cpu_window
rttime_t prev_isr_time
Previous cumulative ISR counter.
rttime_t prev_thread_time[RTOS_MON_MAX_THREADS]
Previous cumulative thread counters.
static struct nodeState states[UWB_SERIAL_COMM_DIST_NUM_NODES]
int ticks
Definition gps_sirf.c:193
void chprintf(BaseSequentialStream *lchp, const char *fmt,...)
Definition printf.c:395
uint16_t foo
Definition main_demo5.c:58
static uint32_t idx
Mini printf-like functionality.
struct rtos_monitoring rtos_mon
Definition rtos_mon.c:30
void shell_add_entry(char *cmd_name, shell_cmd_t *cmd)
Add dynamic entry.
Definition shell_arch.c:91
BaseSequentialStream shell_stream_t
Definition shell_arch.h:31
System monitoring for RTOS targets return cpu load, average exec time, ...
uint8_t cpu_load
global CPU/MCU load in %
char thread_names[RTOS_MON_THREAD_NAMES+1]
string of thread names / identifiers
uint32_t core_free_memory
core free memory in bytes
uint16_t thread_free_stack[RTOS_MON_MAX_THREADS]
individual thread free stack in bytes
uint32_t heap_free_memory
Total fragmented free memory in the heap.
uint16_t thread_load[RTOS_MON_MAX_THREADS]
individual thread load in centi-percent (10*%)
uint8_t thread_name_idx
length of the string in thread_names buffer
uint8_t thread_counter
number of threads
#define RTOS_MON_MAX_THREADS
uint32_t heap_fragments
Number of fragments in the heap.
#define RTOS_MON_NAME_LEN
uint32_t heap_largest
Largest free block in the heap.
Architecture independent timing functions.
Implementation of system time functions for ChibiOS arch.
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
int int32_t
Typedef defining 32 bit int type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
unsigned long long uint64_t
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.