Paparazzi UAS  v5.18.0_stable
Paparazzi is a free software Unmanned Aircraft System.
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  */
29 #include <ch.h>
30 
31 #if !CH_DBG_THREADS_PROFILING
32 #error CH_DBG_THREADS_PROFILING should be defined to TRUE to use this monitoring tool
33 #endif
34 
37 
38 static uint16_t get_stack_free(const thread_t *tp);
39 
40 #if USE_SHELL
41 #include "modules/core/shell.h"
42 #include "printf.h"
43 #include "string.h"
44 #define MAX_CPU_INFO_ENTRIES 20
45 
46 typedef struct _ThreadCpuInfo {
47  float ticks[MAX_CPU_INFO_ENTRIES];
48  float cpu[MAX_CPU_INFO_ENTRIES];
49  float totalTicks;
50 } ThreadCpuInfo ;
51 
52 
53 static void stampThreadCpuInfo (ThreadCpuInfo *ti)
54 {
55  const thread_t *tp = chRegFirstThread();
56  uint32_t idx=0;
57  float totalTicks =0;
58  do {
59  totalTicks+= (float) tp->time;
60  ti->cpu[idx] = (float) tp->time - ti->ticks[idx];;
61  ti->ticks[idx] = (float) tp->time;
62  tp = chRegNextThread ((thread_t *)tp);
63  idx++;
64  } while ((tp != NULL) && (idx < MAX_CPU_INFO_ENTRIES));
65 
66  const float diffTotal = totalTicks- ti->totalTicks;
67  ti->totalTicks = totalTicks;
68  tp = chRegFirstThread();
69  idx=0;
70  do {
71  ti->cpu[idx] = (ti->cpu[idx]*100.f)/diffTotal;
72  tp = chRegNextThread ((thread_t *)tp);
73  idx++;
74  } while ((tp != NULL) && (idx < MAX_CPU_INFO_ENTRIES));
75 }
76 
77 static float stampThreadGetCpuPercent (const ThreadCpuInfo *ti, const uint32_t idx)
78 {
79  if (idx >= MAX_CPU_INFO_ENTRIES)
80  return -1.f;
81  return ti->cpu[idx];
82 }
83 
84 static void cmd_threads(shell_stream_t *lchp, int argc,const char* const argv[]) {
85  static const char *states[] = {CH_STATE_NAMES};
86  thread_t *tp = chRegFirstThread();
87  (void)argv;
88  (void)argc;
89  float totalTicks=0;
90  float idleTicks=0;
91 
92  static ThreadCpuInfo threadCpuInfo = {
93  .ticks = {[0 ... MAX_CPU_INFO_ENTRIES-1] = 0.f},
94  .cpu = {[0 ... MAX_CPU_INFO_ENTRIES-1] =-1.f},
95  .totalTicks = 0.f
96  };
97  stampThreadCpuInfo (&threadCpuInfo);
98 
99  chprintf (lchp, " addr stack frestk prio refs state time \t percent name\r\n");
100  uint32_t idx=0;
101  do {
102  chprintf (lchp, "%.8lx %.8lx %6lu %4lu %4lu %9s %9lu %.1f \t%s\r\n",
103  (uint32_t)tp, (uint32_t)tp->ctx.sp,
104  get_stack_free (tp),
105  (uint32_t)tp->hdr.pqueue.prio, (uint32_t)(tp->refs - 1),
106  states[tp->state], (uint32_t)tp->time,
107  stampThreadGetCpuPercent (&threadCpuInfo, idx),
108  chRegGetThreadNameX(tp));
109  totalTicks+= (float) tp->time;
110  if (strcmp (chRegGetThreadNameX(tp), "idle") == 0)
111  idleTicks = (float) tp->time;
112  tp = chRegNextThread ((thread_t *)tp);
113  idx++;
114  } while (tp != NULL);
115  const float idlePercent = (idleTicks*100.f)/totalTicks;
116  const float cpuPercent = 100.f - idlePercent;
117  chprintf (lchp, "\r\ncpu load = %.2f%%\r\n", cpuPercent);
118 }
119 
120 static void cmd_rtos_mon(shell_stream_t *sh, int argc, const char * const argv[])
121 {
122  (void) argv;
123  if (argc > 0) {
124  chprintf(sh, "Usage: rtos_mon\r\n");
125  return;
126  }
127 
128  chprintf(sh, "Data reported in the RTOS_MON message:\r\n");
129  chprintf(sh, " core free mem: %u\r\n", rtos_mon.core_free_memory);
130  chprintf(sh, " heap free mem: %u\r\n", rtos_mon.heap_free_memory);
131  chprintf(sh, " heap fragments: %u\r\n", rtos_mon.heap_fragments);
132  chprintf(sh, " heap largest: %u\r\n", rtos_mon.heap_largest);
133  chprintf(sh, " CPU load: %d \%\r\n", rtos_mon.cpu_load);
134  chprintf(sh, " number of threads: %d\r\n", rtos_mon.thread_counter);
135  chprintf(sh, " thread names: %s\r\n", rtos_mon.thread_names);
136  for (int i = 0; i < rtos_mon.thread_counter; i++) {
137  chprintf(sh, " thread %d load: %0.1f, free stack: %d\r\n", i,
138  (float)rtos_mon.thread_load[i] / 10.f, rtos_mon.thread_free_stack[i]);
139  }
140  chprintf(sh, " CPU time: %.2f\r\n", rtos_mon.cpu_time);
141 }
142 #endif
143 
145 {
146  idle_counter = 0;
147  last_idle_counter = 0;
148 
149 #if USE_SHELL
150  shell_add_entry("rtos_mon", cmd_rtos_mon);
151  shell_add_entry("threads", cmd_threads);
152 #endif
153 }
154 
155 // Fill data structure
157 {
158  int i;
159  size_t total_fragments, total_fragmented_free_space, largest_free_block;
160  total_fragments = chHeapStatus(NULL, &total_fragmented_free_space, &largest_free_block);
161 
162  rtos_mon.core_free_memory = chCoreGetStatusX();
163  rtos_mon.heap_fragments = total_fragments;
164  rtos_mon.heap_largest = largest_free_block;
165  rtos_mon.heap_free_memory = total_fragmented_free_space;
167 
168  // loop threads to find idle thread
169  // store info on other threads
170  thread_t *tp;
171  float sum = 0.f;
173  tp = chRegFirstThread();
174  do {
175  // add beginning of thread name to buffer
176  for (i = 0; i < RTOS_MON_NAME_LEN-1 && tp->name[i] != '\0'; i++) {
178  }
180 
181  // store free stack for this thread
183 
184  // store time spend in thread
186  sum += (float)(tp->time);
187 
188  // if current thread is 'idle' thread, store its value separately
189  if (tp == chSysGetIdleThreadX()) {
190  idle_counter = (uint32_t)tp->time;
191  }
192  // get next thread
193  tp = chRegNextThread(tp);
194  // increment thread counter
196  } while (tp != NULL && rtos_mon.thread_counter < RTOS_MON_MAX_THREADS);
197 
198  // store individual thread load (as centi-percent integer, i.e. (th_time/sum)*10*100)
199  for (i = 0; i < rtos_mon.thread_counter; i ++) {
200  rtos_mon.thread_load[i] = (uint16_t)(1000.f * (float)thread_p_time[i] / sum);
201  }
202 
203  // assume we call the counter once a second
204  // so the difference in seconds is always one
205  // NOTE: not perfectly precise, +-5% on average so take it into consideration
206  rtos_mon.cpu_load = (uint8_t)((1.f - ((float)idle_counter / sum)) * 100.f);
208 }
209 
210 static uint16_t get_stack_free(const thread_t *tp)
211 {
212  int32_t index = 0;
213  extern const uint8_t __ram0_end__;
214  unsigned long long *stkAdr = (unsigned long long *) ((uint8_t *) tp->wabase);
215  while ((stkAdr[index] == 0x5555555555555555) && ( ((uint8_t *) &(stkAdr[index])) < &__ram0_end__))
216  index++;
217  const int32_t freeBytes = index * (int32_t) sizeof(long long);
218  return (uint16_t)freeBytes;
219 }
220 
uint16_t
unsigned short uint16_t
Definition: types.h:16
states
static struct nodeState states[UWB_SERIAL_COMM_DIST_NUM_NODES]
Definition: decawave_anchorless_communication.c:83
rtos_monitoring::thread_counter
uint8_t thread_counter
number of threads
Definition: sys_mon_rtos.h:52
idle_counter
static uint32_t idle_counter
Definition: rtos_mon_arch.c:36
rtos_monitoring::thread_load
uint16_t thread_load[RTOS_MON_MAX_THREADS]
individual thread load in centi-percent (10*%)
Definition: sys_mon_rtos.h:53
chprintf
void chprintf(BaseSequentialStream *lchp, const char *fmt,...)
Definition: printf.c:395
last_idle_counter
static uint32_t last_idle_counter
Definition: rtos_mon_arch.c:36
rtos_monitoring::heap_largest
uint32_t heap_largest
Largest free block in the heap.
Definition: sys_mon_rtos.h:50
uint32_t
unsigned long uint32_t
Definition: types.h:18
rtos_monitoring::thread_name_idx
uint8_t thread_name_idx
length of the string in thread_names buffer
Definition: sys_mon_rtos.h:56
thread_p_time
static uint32_t thread_p_time[RTOS_MON_MAX_THREADS]
Definition: rtos_mon_arch.c:35
rtos_monitoring::thread_names
char thread_names[RTOS_MON_THREAD_NAMES+1]
string of thread names / identifiers
Definition: sys_mon_rtos.h:55
idx
static uint32_t idx
Definition: nps_radio_control_spektrum.c:105
shell_add_entry
void shell_add_entry(char *cmd_name, shell_cmd_t *cmd)
Add dynamic entry.
Definition: shell_arch.c:85
printf.h
Mini printf-like functionality.
rtos_mon
struct rtos_monitoring rtos_mon
Definition: rtos_mon.c:30
uint8_t
unsigned char uint8_t
Definition: types.h:14
RTOS_MON_NAME_LEN
#define RTOS_MON_NAME_LEN
Definition: sys_mon_rtos.h:40
if
if(GpsFixValid() &&e_identification_started)
Definition: e_identification_fr.c:159
shell_stream_t
BaseSequentialStream shell_stream_t
Definition: shell_arch.h:31
f
uint16_t f
Camera baseline, in meters (i.e. horizontal distance between the two cameras of the stereo setup)
Definition: wedgebug.c:204
rtos_mon_periodic_arch
void rtos_mon_periodic_arch(void)
Definition: rtos_mon_arch.c:156
rtos_monitoring::thread_free_stack
uint16_t thread_free_stack[RTOS_MON_MAX_THREADS]
individual thread free stack in bytes
Definition: sys_mon_rtos.h:54
get_stack_free
static uint16_t get_stack_free(const thread_t *tp)
Definition: rtos_mon_arch.c:210
rtos_monitoring::cpu_time
float cpu_time
Definition: sys_mon_rtos.h:57
rtos_monitoring::heap_free_memory
uint32_t heap_free_memory
Total fragmented free memory in the heap.
Definition: sys_mon_rtos.h:48
sys_mon_rtos.h
int32_t
signed long int32_t
Definition: types.h:19
rtos_monitoring::core_free_memory
uint32_t core_free_memory
core free memory in bytes
Definition: sys_mon_rtos.h:47
ticks
int ticks
Definition: gps_sirf.c:193
rtos_monitoring::heap_fragments
uint32_t heap_fragments
Number of fragments in the heap.
Definition: sys_mon_rtos.h:49
rtos_mon_init_arch
void rtos_mon_init_arch(void)
Definition: rtos_mon_arch.c:144
shell.h
rtos_monitoring::cpu_load
uint8_t cpu_load
global CPU/MCU load in %
Definition: sys_mon_rtos.h:51
RTOS_MON_MAX_THREADS
#define RTOS_MON_MAX_THREADS
Definition: sys_mon_rtos.h:36