source: rtems/cpukit/libmisc/cpuuse/cpuusagetop.c @ 4123e244

4.115
Last change on this file since 4123e244 was 4123e244, checked in by Jennifer Averett <jennifer.averett@…>, on 11/03/14 at 12:56:00

cpuuse: Resolve compile errors.

  • Property mode set to 100644
File size: 10.3 KB
Line 
1/**
2 * @file
3 *
4 * @brief CPU Usage Top
5 * @ingroup libmisc_cpuuse CPU Usage
6 */
7
8/*
9 *  COPYRIGHT (c) 2014.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.org/license/LICENSE.
15 */
16
17#ifdef HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <string.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include <rtems/cpuuse.h>
28#include <rtems/score/objectimpl.h>
29#include <rtems/score/threadimpl.h>
30#include <rtems/score/todimpl.h>
31#include <rtems/score/watchdogimpl.h>
32
33/*
34 * Common variable to sync the load monitor task.
35 */
36static volatile int rtems_cpuusage_top_thread_active;
37
38typedef struct {
39  void                  *context;
40  rtems_printk_plugin_t  print;
41}rtems_cpu_usage_plugin_t;
42
43#define RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS (20)
44
45
46static inline bool equal_to_uint32_t( uint32_t * lhs, uint32_t * rhs )
47{
48   if ( *lhs == *rhs )
49     return true;
50   else
51     return false;
52}
53
54static inline bool less_than_uint32_t( uint32_t * lhs, uint32_t * rhs )
55{
56   if ( *lhs < *rhs )
57    return true;
58   else
59    return false;
60}
61
62#ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
63  #define _Thread_CPU_usage_Equal_to( _lhs, _rhs ) \
64          _Timestamp_Equal_to( _lhs, _rhs )
65#else
66  #define _Thread_CPU_usage_Equal_to( _lhs, _rhs ) \
67          equal_to_uint32_t( _lhs, _rhs )
68#endif
69
70#ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
71#define  _Thread_CPU_usage_Set_to_zero( _time ) \
72         _Timestamp_Set_to_zero( _time )
73#else
74#define  _Thread_CPU_usage_Set_to_zero( _time ) \
75       do { \
76         *_time = 0; \
77       } while (0)
78#endif
79
80#ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
81#define _Thread_CPU_usage_Less_than( _lhs, _rhs ) \
82        _Timestamp_Less_than( _lhs, _rhs )
83#else
84#define _Thread_CPU_usage_Less_than( _lhs, _rhs ) \
85         less_than_uint32_t( _lhs, _rhs )
86#endif
87
88/*
89 * rtems_cpuusage_top_thread
90 *
91 * This function displays the load of the tasks on an ANSI terminal.
92 */
93
94static void
95rtems_cpuusage_top_thread (rtems_task_argument arg)
96{
97  uint32_t                  api_index;
98  Thread_Control*           the_thread;
99  int                       i;
100  int                       j;
101  int                       k;
102  Objects_Information*      information;
103  char                      name[13];
104  int                       task_count = 0;
105  uint32_t                  seconds, nanoseconds;
106  rtems_cpu_usage_plugin_t* plugin = (rtems_cpu_usage_plugin_t*)arg;
107  Thread_Control*           load_tasks[RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS + 1];
108  Thread_CPU_usage_t        load[RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS + 1];
109  Thread_CPU_usage_t        zero;
110  Timestamp_Control         uptime;
111  uint32_t                  ival, fval;
112
113  while (true) {
114    #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
115      Timestamp_Control  total, ran, uptime_at_last_reset;
116    #else
117      uint32_t           total_units = 0;
118    #endif
119
120    rtems_cpuusage_top_thread_active = 1;
121
122    _Thread_CPU_usage_Set_to_zero( &zero);
123    memset (load_tasks, 0, sizeof (load_tasks));
124    for (i=0; i< (RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS + 1); i++)
125      _Thread_CPU_usage_Set_to_zero( &load[i] );
126
127   /*
128     * Iterate over the tasks and sort the highest load tasks
129     * into our local arrays. We only handle a limited number of
130     * tasks.
131     */
132    for ( api_index = 1 ; api_index <= OBJECTS_APIS_LAST ; api_index++ ) {
133      #if !defined(RTEMS_POSIX_API) || defined(RTEMS_DEBUG)
134        if ( !_Objects_Information_table[ api_index ] )
135          continue;
136      #endif
137
138      information = _Objects_Information_table[ api_index ][ 1 ];
139      if ( information ) {
140        for ( i=1 ; i <= information->maximum ; i++ ) {
141          the_thread = (Thread_Control *)information->local_table[ i ];
142          if ( the_thread ) {
143            Thread_CPU_usage_t usage = the_thread->cpu_time_used;
144
145            /*
146             *  When not using nanosecond CPU usage resolution, we have to count
147             *  the number of "ticks" we gave credit for to give the user a rough
148             *  guideline as to what each number means proportionally.
149             */
150            #ifdef __RTEMS_USE_TICKS_FOR_STATISTICS__
151              total_units += usage;
152            #endif
153
154            /* Count the number of tasks and sort this load value */
155            task_count++;
156            for (j = 0; j < RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS; j++) {
157              if (load_tasks[j]) {
158                if ( _Thread_CPU_usage_Equal_to( &usage, &zero) ||
159                     _Thread_CPU_usage_Less_than( &usage, &load[j]))
160                  continue;
161                for (k = (RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS - 1); k >= j; k--){
162                  load_tasks[k + 1] = load_tasks[k];
163                  load[k + 1]  = load[k];
164                }
165              }
166              load_tasks[j] = the_thread;
167              load[j]  = usage;
168              break;
169            }
170          }
171        }
172      }
173    }
174
175    #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
176      _Timestamp_Set_to_zero( &total );
177      uptime_at_last_reset = CPU_usage_Uptime_at_last_reset;
178    #endif
179
180    _TOD_Get_uptime( &uptime );
181    seconds = _Timestamp_Get_seconds( &uptime );
182    nanoseconds = _Timestamp_Get_nanoseconds( &uptime ) /
183                  TOD_NANOSECONDS_PER_MICROSECOND;
184    (*plugin->print)(plugin->context, "\x1b[H\x1b[J Press ENTER to exit.\n\n");
185    (*plugin->print)(plugin->context, "uptime: ");
186    (*plugin->print)(plugin->context,
187      "%7" PRIu32 ".%06" PRIu32 "\n",  seconds, nanoseconds
188    );
189
190    (*plugin->print)(
191       plugin->context,
192       "-------------------------------------------------------------------------------\n"
193       "                              CPU USAGE BY THREAD\n"
194       "------------+---------------------+---------------+---------------+------------\n"
195       #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
196        " ID         | NAME                | RPRI | CPRI   | SECONDS       | PERCENT\n"
197       #else
198        " ID         | NAME                | RPRI | CPRI   | TICKS         | PERCENT\n"
199       #endif
200       "------------+---------------------+---------------+---------------+------------\n"
201    );
202
203    for (i = 0; i < RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS; i++) {
204
205      if (!load_tasks[i])
206        break;
207
208      /*
209       * If this is the currently executing thread, account for time
210       * since the last context switch.
211       */
212      the_thread = load_tasks[i];
213
214      rtems_object_get_name( the_thread->Object.id, sizeof(name), name );
215      (*plugin->print)(
216        plugin->context,
217        " 0x%08" PRIx32 " | %-19s |  %3" PRId32 " |  %3" PRId32 "   |",
218        the_thread->Object.id,
219        name,
220        the_thread->real_priority,
221        the_thread->current_priority
222      );
223
224      #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
225      {
226        Timestamp_Control last;
227
228        /*
229         * If this is the currently executing thread, account for time
230         * since the last context switch.
231         */
232        ran = load[i];
233        if ( _Thread_Get_time_of_last_context_switch( the_thread, &last ) ) {
234          Timestamp_Control used;
235          _TOD_Get_uptime( &uptime );
236          _Timestamp_Subtract( &last, &uptime, &used );
237          _Timestamp_Add_to( &ran, &used );
238        } else {
239          _TOD_Get_uptime( &uptime );
240        }
241        _Timestamp_Subtract( &uptime_at_last_reset, &uptime, &total );
242        _Timestamp_Divide( &ran, &total, &ival, &fval );
243
244        /*
245         * Print the information
246         */
247
248        seconds = _Timestamp_Get_seconds( &ran );
249        nanoseconds = _Timestamp_Get_nanoseconds( &ran ) /
250          TOD_NANOSECONDS_PER_MICROSECOND;
251       (*plugin->print)( plugin->context,
252          "%7" PRIu32 ".%06" PRIu32 " |%4" PRIu32 ".%03" PRIu32 "\n",
253          seconds, nanoseconds,
254            ival, fval
255        );
256      }
257      #else
258        if (total_units) {
259          uint64_t ival_64;
260
261          ival_64 = load[i];
262          ival_64 *= 100000;
263          ival = ival_64 / total_units;
264        } else {
265          ival = 0;
266        }
267
268        fval = ival % 1000;
269        ival /= 1000;
270       (*plugin->print)( plugin->context,
271          "%14" PRIu32 " |%4" PRIu32 ".%03" PRIu32 "\n",
272          load[i],
273          ival,
274          fval
275        );
276      #endif
277    }
278
279    if (task_count < RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS)
280    {
281      j = RTEMS_CPUUSAGE_TOP_MAX_LOAD_TASKS - task_count;
282      while (j > 0)
283      {
284       (*plugin->print)( plugin->context, "\x1b[K\n");
285        j--;
286      }
287    }
288
289    rtems_cpuusage_top_thread_active = 0;
290
291    rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (5000000));
292  }
293}
294
295void rtems_cpu_usage_top_with_plugin(
296  void                  *context,
297  rtems_printk_plugin_t  print
298)
299{
300  rtems_status_code   sc;
301  rtems_task_priority priority;
302  rtems_name          name;
303  rtems_id            id;
304  rtems_cpu_usage_plugin_t  plugin;
305
306  if ( !print )
307    return;
308
309  plugin.context = context;
310  plugin.print   = print;
311
312  sc = rtems_task_set_priority (RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority);
313
314  if (sc != RTEMS_SUCCESSFUL)
315  {
316    (*print)(
317       context,
318       "error: cannot obtain the current priority: %s\n",
319       rtems_status_text (sc)
320    );
321    return;
322  }
323
324  name = rtems_build_name('C', 'P', 'l', 't');
325
326  sc = rtems_task_create (name, priority, 4 * 1024,
327                          RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
328                          RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR,
329                          &id);
330
331  if (sc != RTEMS_SUCCESSFUL)
332  {
333    (*print)(
334       context,
335       "error: cannot create helper thread: %s\n",
336       rtems_status_text (sc)
337    );
338    return;
339  }
340
341  sc = rtems_task_start (
342    id, rtems_cpuusage_top_thread, (rtems_task_argument)&plugin
343  );
344  if (sc != RTEMS_SUCCESSFUL)
345  {
346    (*print)(
347       context,
348       "error: cannot start helper thread: %s\n",
349       rtems_status_text (sc)
350    );
351    rtems_task_delete (id);
352    return;
353  }
354
355  for (;;)
356  {
357    int c = getchar ();
358
359    if ((c == '\r') || (c == '\n'))
360    {
361      int loops = 20;
362
363      while (loops && rtems_cpuusage_top_thread_active)
364        rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (100000));
365
366      rtems_task_delete (id);
367
368      (*print)(context, "load monitoring stopped.\n");
369      return;
370    }
371  }
372}
373
374void rtems_cpu_usage_top( void )
375{
376  rtems_cpu_usage_top_with_plugin( NULL, printk_plugin );
377}
Note: See TracBrowser for help on using the repository browser.