source: rtems/cpukit/libmisc/cpuuse/cpuusagereport.c @ 21242c2

4.115
Last change on this file since 21242c2 was c1a84bf8, checked in by Joel Sherrill <joel.sherrill@…>, on 06/16/11 at 16:24:05

2011-06-16 Joel Sherrill <joel.sherrill@…>

PR 1818/misc

  • libmisc/cpuuse/cpuusagereport.c: Add SMP support to CPU Usage Reporting.
  • Property mode set to 100644
File size: 6.8 KB
Line 
1/*
2 *  CPU Usage Reporter
3 *
4 *  COPYRIGHT (c) 1989-2010.
5 *  On-Line Applications Research Corporation (OAR).
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.com/license/LICENSE.
10 *
11 *  $Id$
12 */
13
14#ifdef HAVE_CONFIG_H
15#include "config.h"
16#endif
17
18#include <rtems.h>
19
20#include <string.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <ctype.h>
24#include <inttypes.h>
25
26#include <rtems/cpuuse.h>
27#include <rtems/bspIo.h>
28
29#ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
30  #include <rtems/score/timestamp.h>
31#endif
32
33#ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
34  extern Timestamp_Control  CPU_usage_Uptime_at_last_reset;
35#else
36  extern uint32_t           CPU_usage_Ticks_at_last_reset;
37#endif
38
39#ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
40  static bool is_executing_on_a_core(
41    Thread_Control    *the_thread,
42    Timestamp_Control *time_of_context_switch
43  )
44  {
45    #ifndef RTEMS_SMP
46      if ( _Thread_Executing->Object.id == the_thread->Object.id ) {
47        *time_of_context_switch = _Thread_Time_of_last_context_switch;
48        return true;
49      }
50    #else
51      int  cpu;
52      for ( cpu=0 ; cpu < _SMP_Processor_count ; cpu++ ) {
53        Per_CPU_Control *p = &_Per_CPU_Information[cpu];
54        if ( p->executing->Object.id == the_thread->Object.id ) {
55          *time_of_context_switch = p->time_of_last_context_switch;
56          return true;
57        }
58      }
59    #endif
60    return false;
61  }
62#endif
63
64/*
65 *  rtems_cpu_usage_report
66 */
67void rtems_cpu_usage_report_with_plugin(
68  void                  *context,
69  rtems_printk_plugin_t  print
70)
71{
72  uint32_t             i;
73  uint32_t             api_index;
74  Thread_Control      *the_thread;
75  Objects_Information *information;
76  char                 name[13];
77  uint32_t             ival, fval;
78  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
79    Timestamp_Control  uptime, total, ran, uptime_at_last_reset;
80  #else
81    uint32_t           total_units = 0;
82  #endif
83
84  if ( !print )
85    return;
86
87  /*
88   *  When not using nanosecond CPU usage resolution, we have to count
89   *  the number of "ticks" we gave credit for to give the user a rough
90   *  guideline as to what each number means proportionally.
91   */
92  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
93    _Timestamp_Set_to_zero( &total );
94    uptime_at_last_reset = CPU_usage_Uptime_at_last_reset;
95  #else
96    for ( api_index = 1 ; api_index <= OBJECTS_APIS_LAST ; api_index++ ) {
97      #if !defined(RTEMS_POSIX_API) || defined(RTEMS_DEBUG)
98        if ( !_Objects_Information_table[ api_index ] )
99          continue;
100      #endif
101
102      information = _Objects_Information_table[ api_index ][ 1 ];
103      if ( information ) {
104        for ( i=1 ; i <= information->maximum ; i++ ) {
105          the_thread = (Thread_Control *)information->local_table[ i ];
106
107          if ( the_thread )
108            total_units += the_thread->cpu_time_used;
109        }
110      }
111    }
112  #endif
113
114  (*print)(
115     context,
116     "-------------------------------------------------------------------------------\n"
117     "                              CPU USAGE BY THREAD\n"
118     "------------+----------------------------------------+---------------+---------\n"
119     #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
120       " ID         | NAME                                   | SECONDS       | PERCENT\n"
121     #else
122       " ID         | NAME                                   | TICKS         | PERCENT\n"
123     #endif
124     "------------+----------------------------------------+---------------+---------\n"
125  );
126
127  for ( api_index = 1 ; api_index <= OBJECTS_APIS_LAST ; api_index++ ) {
128    #if !defined(RTEMS_POSIX_API) || defined(RTEMS_DEBUG)
129      if ( !_Objects_Information_table[ api_index ] )
130        continue;
131    #endif
132
133    information = _Objects_Information_table[ api_index ][ 1 ];
134    if ( information ) {
135      for ( i=1 ; i <= information->maximum ; i++ ) {
136        the_thread = (Thread_Control *)information->local_table[ i ];
137
138        if ( !the_thread )
139          continue;
140
141        rtems_object_get_name( the_thread->Object.id, sizeof(name), name );
142
143        (*print)(
144          context,
145          " 0x%08" PRIx32 " | %-38s |",
146          the_thread->Object.id,
147          name
148        );
149
150        #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
151        {
152          Timestamp_Control last;
153
154          /*
155           * If this is the currently executing thread, account for time
156           * since the last context switch.
157           */
158          ran = the_thread->cpu_time_used;
159          if ( is_executing_on_a_core( the_thread, &last ) ) {
160            Timestamp_Control used;
161            _TOD_Get_uptime( &uptime );
162            _Timestamp_Subtract( &last, &uptime, &used );
163            _Timestamp_Add_to( &ran, &used );
164          } else {
165            _TOD_Get_uptime( &uptime );
166          }
167          _Timestamp_Subtract( &uptime_at_last_reset, &uptime, &total );
168          _Timestamp_Divide( &ran, &total, &ival, &fval );
169
170          /*
171           * Print the information
172           */
173
174          (*print)( context,
175            "%7" PRIu32 ".%06" PRIu32 " |%4" PRIu32 ".%03" PRIu32 "\n",
176            _Timestamp_Get_seconds( &ran ),
177            _Timestamp_Get_nanoseconds( &ran ) /
178               TOD_NANOSECONDS_PER_MICROSECOND,
179            ival, fval
180          );
181        }
182        #else
183         if (total_units) {
184            uint64_t ival_64;
185
186            ival_64 = the_thread->cpu_time_used;
187            ival_64 *= 100000;
188            ival = ival_64 / total_units;
189          } else {
190            ival = 0;
191          }
192
193          fval = ival % 1000;
194          ival /= 1000;
195          (*print)( context,
196            "%14" PRIu32 " |%4" PRIu32 ".%03" PRIu32 "\n",
197            the_thread->cpu_time_used,
198            ival,
199            fval
200          );
201        #endif
202      }
203    }
204  }
205
206  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
207    (*print)(
208       context,
209       "------------+----------------------------------------+---------------+---------\n"
210       " TIME SINCE LAST CPU USAGE RESET IN SECONDS:                    %7" PRIu32 ".%06" PRIu32 "\n"
211       "-------------------------------------------------------------------------------\n",
212       _Timestamp_Get_seconds( &total ),
213       _Timestamp_Get_nanoseconds( &total ) / TOD_NANOSECONDS_PER_MICROSECOND
214    );
215  #else
216    (*print)(
217       context,
218       "------------+----------------------------------------+---------------+---------\n"
219       " TICKS SINCE LAST SYSTEM RESET:                                 %14" PRIu32 "\n"
220       " TOTAL UNITS:                                                   %14" PRIu32 "\n"
221       "-------------------------------------------------------------------------------\n",
222       _Watchdog_Ticks_since_boot - CPU_usage_Ticks_at_last_reset,
223       total_units
224    );
225  #endif
226}
227
228void rtems_cpu_usage_report( void )
229{
230  rtems_cpu_usage_report_with_plugin( NULL, printk_plugin );
231}
Note: See TracBrowser for help on using the repository browser.