PX4 Firmware
PX4 Autopilot Software http://px4.io
print_load_nuttx.c
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2015 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file printload.c
36  *
37  * Print the current system load.
38  *
39  * @author Lorenz Meier <lorenz@px4.io>
40  */
41 
42 #include <string.h>
43 #include <stdio.h>
44 
45 #include <systemlib/cpuload.h>
46 #include <systemlib/printload.h>
47 #include <drivers/drv_hrt.h>
48 
49 #if defined(BOARD_DMA_ALLOC_POOL_SIZE)
50 #include <px4_platform/board_dma_alloc.h>
51 #endif /* BOARD_DMA_ALLOC_POOL_SIZE */
52 
53 #if defined(CONFIG_SCHED_INSTRUMENTATION)
54 
55 #if !defined(CONFIG_TASK_NAME_SIZE)
56 #error print_load_nuttx requires CONFIG_TASK_NAME_SIZE
57 #endif
58 
59 #if !defined(CONFIG_STACK_COLORATION)
60 #error print_load_nuttx requires CONFIG_STACK_COLORATION
61 #endif
62 
63 extern struct system_load_s system_load;
64 
65 #define CL "\033[K" // clear line
66 
67 void init_print_load_s(uint64_t t, struct print_load_s *s)
68 {
69 
70  s->total_user_time = 0;
71 
72  s->running_count = 0;
73  s->blocked_count = 0;
74 
75  s->new_time = t;
76  s->interval_start_time = t;
77 
78  for (int i = 0; i < CONFIG_MAX_TASKS; i++) {
79  s->last_times[i] = 0;
80  }
81 
82  s->interval_time_ms_inv = 0.f;
83 }
84 
85 static const char *
86 tstate_name(const tstate_t s)
87 {
88  switch (s) {
89  case TSTATE_TASK_INVALID:
90  return "init";
91 
92  case TSTATE_TASK_PENDING:
93  return "PEND";
94 
95  case TSTATE_TASK_READYTORUN:
96  return "READY";
97 
98  case TSTATE_TASK_RUNNING:
99  return "RUN";
100 
101  case TSTATE_TASK_INACTIVE:
102  return "inact";
103 
104  case TSTATE_WAIT_SEM:
105  return "w:sem";
106 #ifndef CONFIG_DISABLE_SIGNALS
107 
108  case TSTATE_WAIT_SIG:
109  return "w:sig";
110 #endif
111 #ifndef CONFIG_DISABLE_MQUEUE
112 
113  case TSTATE_WAIT_MQNOTEMPTY:
114  return "w:mqe";
115 
116  case TSTATE_WAIT_MQNOTFULL:
117  return "w:mqf";
118 #endif
119 #ifdef CONFIG_PAGING
120 
121  case TSTATE_WAIT_PAGEFILL:
122  return "w:pgf";
123 #endif
124 
125  default:
126  return "ERROR";
127  }
128 }
129 
130 void print_load_buffer(uint64_t t, char *buffer, int buffer_length, print_load_callback_f cb, void *user,
131  struct print_load_s *print_state)
132 {
133 #pragma GCC diagnostic push
134 #pragma GCC diagnostic ignored "-Wformat" // NuttX uses a different printf format
135 #pragma GCC diagnostic ignored "-Wformat-extra-args"
136  print_state->new_time = t;
137 
138  int i;
139  uint64_t curr_time_us;
140  uint64_t idle_time_us;
141  float idle_load = 0.f;
142 
143  curr_time_us = t;
144  idle_time_us = system_load.tasks[0].total_runtime;
145 
146  if (print_state->new_time > print_state->interval_start_time) {
147  print_state->interval_time_ms_inv = 1.f / ((float)((print_state->new_time - print_state->interval_start_time) / 1000));
148 
149  /* header for task list */
150  snprintf(buffer, buffer_length, "%4s %-*s %8s %6s %11s %10s %-5s %2s",
151  "PID",
152  CONFIG_TASK_NAME_SIZE, "COMMAND",
153  "CPU(ms)",
154  "CPU(%)",
155  "USED/STACK",
156  "PRIO(BASE)",
157 #if CONFIG_RR_INTERVAL > 0
158  "TSLICE",
159 #else
160  "STATE",
161 #endif
162  "FD"
163  );
164  cb(user);
165 
166  }
167 
168  print_state->running_count = 0;
169  print_state->blocked_count = 0;
170  print_state->total_user_time = 0;
171 
172  // create a copy of the runtimes because this could be updated during the print output
173  uint32_t total_runtime[CONFIG_MAX_TASKS];
174 
175  for (i = 0; i < CONFIG_MAX_TASKS; i++) {
176  total_runtime[i] = (uint32_t)(system_load.tasks[i].total_runtime / 1000);
177  }
178 
179  for (i = 0; i < CONFIG_MAX_TASKS; i++) {
180 
181  sched_lock(); // need to lock the tcb access (but make it as short as possible)
182 
183  if (!system_load.tasks[i].valid) {
184  sched_unlock();
185  continue;
186  }
187 
188  uint64_t interval_runtime;
189  unsigned tcb_pid = system_load.tasks[i].tcb->pid;
190  size_t stack_size = system_load.tasks[i].tcb->adj_stack_size;
191  ssize_t stack_free = 0;
192  char tcb_name[CONFIG_TASK_NAME_SIZE + 1];
193  strncpy(tcb_name, system_load.tasks[i].tcb->name, CONFIG_TASK_NAME_SIZE + 1);
194 
195 #if CONFIG_ARCH_INTERRUPTSTACK > 3
196 
197  if (system_load.tasks[i].tcb->pid == 0) {
198  stack_size = (CONFIG_ARCH_INTERRUPTSTACK & ~3);
199  stack_free = up_check_intstack_remain();
200 
201  } else {
202  stack_free = up_check_tcbstack_remain(system_load.tasks[i].tcb);
203  }
204 
205 #else
206  stack_free = up_check_tcbstack_remain(system_load.tasks[i].tcb);
207 #endif
208 
209 #if CONFIG_ARCH_BOARD_SIM || !defined(CONFIG_PRIORITY_INHERITANCE)
210 #else
211  unsigned tcb_base_priority = system_load.tasks[i].tcb->base_priority;
212 #endif
213 #if CONFIG_RR_INTERVAL > 0
214  unsigned tcb_timeslice = system_load.tasks[i].tcb->timeslice;
215 #endif
216  unsigned tcb_task_state = system_load.tasks[i].tcb->task_state;
217  unsigned tcb_sched_priority = system_load.tasks[i].tcb->sched_priority;
218 
219  unsigned int tcb_num_used_fds = 0; // number of used file descriptors
220 #if CONFIG_NFILE_DESCRIPTORS > 0
221  FAR struct task_group_s *group = system_load.tasks[i].tcb->group;
222 
223  if (group) {
224  for (int fd_index = 0; fd_index < CONFIG_NFILE_DESCRIPTORS; ++fd_index) {
225  if (group->tg_filelist.fl_files[fd_index].f_inode) {
226  ++tcb_num_used_fds;
227  }
228  }
229  }
230 
231 #endif
232 
233  sched_unlock();
234 
235  switch (tcb_task_state) {
236  case TSTATE_TASK_PENDING:
237  case TSTATE_TASK_READYTORUN:
238  case TSTATE_TASK_RUNNING:
239  print_state->running_count++;
240  break;
241 
242 #ifndef CONFIG_DISABLE_SIGNALS
243 
244  case TSTATE_WAIT_SIG:
245 #endif
246 #ifndef CONFIG_DISABLE_MQUEUE
247  case TSTATE_WAIT_MQNOTEMPTY:
248  case TSTATE_WAIT_MQNOTFULL:
249 #endif
250 #ifdef CONFIG_PAGING
251  case TSTATE_WAIT_PAGEFILL:
252 #endif
253  case TSTATE_TASK_INVALID:
254  case TSTATE_TASK_INACTIVE:
255  case TSTATE_WAIT_SEM:
256  print_state->blocked_count++;
257  break;
258  }
259 
260  interval_runtime = (print_state->last_times[i] > 0 && total_runtime[i] > print_state->last_times[i])
261  ? (total_runtime[i] - print_state->last_times[i]) : 0;
262 
263  print_state->last_times[i] = total_runtime[i];
264 
265  float current_load = 0.f;
266 
267  if (print_state->new_time > print_state->interval_start_time) {
268  current_load = interval_runtime * print_state->interval_time_ms_inv;
269 
270  if (tcb_pid != 0) {
271  print_state->total_user_time += interval_runtime;
272 
273  } else {
274  idle_load = current_load;
275  }
276 
277  }
278 
279 
280  if (print_state->new_time <= print_state->interval_start_time) {
281  continue; // not enough data yet
282  }
283 
284  // print output
285  int print_len = snprintf(buffer, buffer_length, "%4d %-*s %8d %2d.%03d %5u/%5u %3u (%3u) ",
286  tcb_pid,
287  CONFIG_TASK_NAME_SIZE, tcb_name,
288  total_runtime[i],
289  (int)(current_load * 100.0f),
290  (int)((current_load * 100.0f - (int)(current_load * 100.0f)) * 1000),
291  stack_size - stack_free,
292  stack_size,
293  tcb_sched_priority,
294 #if CONFIG_ARCH_BOARD_SIM || !defined(CONFIG_PRIORITY_INHERITANCE)
295  0);
296 #else
297  tcb_base_priority);
298 #endif
299 #if CONFIG_RR_INTERVAL > 0
300  /* print scheduling info with RR time slice */
301  snprintf(buffer + print_len, buffer_length - print_len, " %5d %2d", tcb_timeslice, tcb_num_used_fds);
302  (void)tstate_name(TSTATE_TASK_INVALID); // Stop not used warning
303 #else
304  // print task state instead
305  snprintf(buffer + print_len, buffer_length - print_len, " %-5s %2d", tstate_name(tcb_task_state), tcb_num_used_fds);
306 #endif
307  cb(user);
308  }
309 
310  if (print_state->new_time <= print_state->interval_start_time) {
311  // first run, not enough data yet
312  return;
313  }
314 
315  // Print footer
316  buffer[0] = 0;
317  cb(user);
318  float task_load;
319  float sched_load;
320 
321  task_load = (float)(print_state->total_user_time) * print_state->interval_time_ms_inv;
322 
323  /* this can happen if one tasks total runtime was not computed
324  correctly by the scheduler instrumentation TODO */
325  if (task_load > (1.f - idle_load)) {
326  task_load = (1.f - idle_load);
327  }
328 
329  sched_load = 1.f - idle_load - task_load;
330 
331  snprintf(buffer, buffer_length, "Processes: %d total, %d running, %d sleeping, max FDs: %d",
332  system_load.total_count,
333  print_state->running_count,
334  print_state->blocked_count,
335  CONFIG_NFILE_DESCRIPTORS);
336  cb(user);
337  snprintf(buffer, buffer_length, "CPU usage: %.2f%% tasks, %.2f%% sched, %.2f%% idle",
338  (double)(task_load * 100.f),
339  (double)(sched_load * 100.f),
340  (double)(idle_load * 100.f));
341  cb(user);
342 #if defined(BOARD_DMA_ALLOC_POOL_SIZE)
343  uint16_t dma_total;
344  uint16_t dma_used;
345  uint16_t dma_peak_used;
346 
347  if (board_get_dma_usage(&dma_total, &dma_used, &dma_peak_used) >= 0) {
348  snprintf(buffer, buffer_length, "DMA Memory: %d total, %d used %d peak",
349  dma_total,
350  dma_used,
351  dma_peak_used);
352  cb(user);
353  }
354 
355 #endif
356  snprintf(buffer, buffer_length, "Uptime: %.3fs total, %.3fs idle",
357  (double)curr_time_us / 1000000.d,
358  (double)idle_time_us / 1000000.d);
359  cb(user);
360 
361  print_state->interval_start_time = print_state->new_time;
362 
363 #pragma GCC diagnostic pop
364 }
365 
366 
367 struct print_load_callback_data_s {
368  int fd;
369  char buffer[140];
370 };
371 
372 static void print_load_callback(void *user)
373 {
374  char *clear_line = "";
375  struct print_load_callback_data_s *data = (struct print_load_callback_data_s *)user;
376 
377  if (data->fd == 1) {
378  clear_line = CL;
379  }
380 
381  dprintf(data->fd, "%s%s\n", clear_line, data->buffer);
382 }
383 
384 void print_load(uint64_t t, int fd, struct print_load_s *print_state)
385 {
386  /* print system information */
387  if (fd == 1) {
388  dprintf(fd, "\033[H"); /* move cursor home and clear screen */
389  }
390 
391  struct print_load_callback_data_s data;
392 
393  data.fd = fd;
394 
395  print_load_buffer(t, data.buffer, sizeof(data.buffer), print_load_callback, &data, print_state);
396 }
397 
398 #endif // if CONFIG_SCHED_INSTRUMENTATION
uint64_t new_time
Definition: printload.h:58
High-resolution timer with callouts and timekeeping.
void(* print_load_callback_f)(void *user)
Definition: printload.h:71
Print the current system load.
uint8_t * data
Definition: dataman.cpp:149
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
#define CONFIG_MAX_TASKS
Definition: printload.h:49
int blocked_count
Definition: printload.h:56
int fd
Definition: dataman.cpp:146
float interval_time_ms_inv
Definition: printload.h:61
uint64_t interval_start_time
Definition: printload.h:59
uint64_t total_user_time
Definition: printload.h:53
uint32_t last_times[CONFIG_MAX_TASKS]
Definition: printload.h:60
static const char * tstate_name(const tstate_t s)
Definition: resources.cpp:49
int running_count
Definition: printload.h:55