source: rtems/cpukit/libmisc/cpuuse/cpuusagetop.c @ 6031da4

4.115
Last change on this file since 6031da4 was 6031da4, checked in by Jennifer Averett <jennifer.averett@…>, on 09/29/14 at 15:20:27

libmisc: Add top to cpuusage.

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