source: rtems/cpukit/rtems/src/ratemonperiod.c @ 94d9bee

4.104.115
Last change on this file since 94d9bee was 94d9bee, checked in by Joel Sherrill <joel.sherrill@…>, on 10/30/09 at 17:54:29

2009-10-30 Glenn Humphrey <glenn.humphrey@…>

PR pr1462/cpukit

  • rtems/include/rtems/rtems/ratemon.h, rtems/src/ratemongetstatus.c, rtems/src/ratemonperiod.c, rtems/src/ratemontimeout.c, score/include/rtems/score/thread.h: Fix bugs in rate monotonic statistics.
  • Property mode set to 100644
File size: 9.9 KB
Line 
1/*
2 *  Rate Monotonic Manager - Period Blocking and Status
3 *
4 *  COPYRIGHT (c) 1989-2009.
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#if HAVE_CONFIG_H
15#include "config.h"
16#endif
17
18#include <rtems/system.h>
19#include <rtems/rtems/status.h>
20#include <rtems/rtems/support.h>
21#include <rtems/score/isr.h>
22#include <rtems/score/object.h>
23#include <rtems/rtems/ratemon.h>
24#include <rtems/score/thread.h>
25
26void _Rate_monotonic_Initiate_statistics(
27  Rate_monotonic_Control *the_period
28)
29{
30  Thread_Control *owning_thread = the_period->owner;
31
32  /*
33   *  If any statistics are at nanosecond granularity, we need to
34   *  obtain the uptime.
35   */
36  #if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS) || \
37      defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
38
39    struct timespec  uptime;
40
41    _TOD_Get_uptime( &uptime );
42  #endif
43
44  /*
45   *  Set the starting point and the CPU time used for the statistics.
46   */
47  #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
48    the_period->time_at_period = uptime;
49  #else
50    the_period->time_at_period = _Watchdog_Ticks_since_boot;
51  #endif
52
53  the_period->owner_executed_at_period = owning_thread->cpu_time_used;
54
55  /*
56   *  If using nanosecond granularity for CPU Usage Statistics and the
57   *  period's thread is currently executing, then we need to take into
58   *  account how much time the executing thread has run since the last
59   *  context switch.  When this routine is invoked from
60   *  rtems_rate_monotonic_period, the owner will be the executing thread.
61   *  When this routine is invoked from _Rate_monotonic_Timeout, it will not.
62   */
63  #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
64    if (owning_thread == _Thread_Executing) {
65
66      rtems_thread_cpu_usage_t ran;
67
68      /*
69       *  Adjust the CPU time used to account for the time since last
70       *  context switch.
71       */
72      _Timespec_Subtract(
73        &_Thread_Time_of_last_context_switch, &uptime, &ran
74      );
75
76      _Timespec_Add_to( &the_period->owner_executed_at_period, &ran );
77    }
78  #endif
79}
80
81void _Rate_monotonic_Update_statistics(
82  Rate_monotonic_Control    *the_period
83)
84{
85  Rate_monotonic_Statistics      *stats;
86  Thread_CPU_usage_t              executed;
87  Rate_monotonic_Period_time_t    since_last_period;
88  #if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS) || \
89      defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
90    Timestamp_Control             uptime;
91
92    /*
93     * Obtain the current time since boot
94     */
95    _TOD_Get_uptime( &uptime );
96  #endif
97
98  /*
99   *  Assume we are only called in states where it is appropriate
100   *  to update the statistics.  This should only be RATE_MONOTONIC_ACTIVE
101   *  and RATE_MONOTONIC_EXPIRED.
102   */
103
104  /*
105   *  Update the counts.
106   */
107
108  stats = &the_period->Statistics;
109  stats->count++;
110
111  if ( the_period->state == RATE_MONOTONIC_EXPIRED )
112    stats->missed_count++;
113
114  /*
115   *  Grab basic information for time statistics.
116   */
117
118  #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
119    _Timestamp_Subtract(
120      &the_period->time_at_period, &uptime, &since_last_period
121    );
122    the_period->time_at_period = uptime;
123  #else
124    since_last_period = _Watchdog_Ticks_since_boot - the_period->time_at_period;
125    the_period->time_at_period = _Watchdog_Ticks_since_boot;
126  #endif
127
128  #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
129    {
130      Thread_CPU_usage_t ran, used;
131       
132      /* Grab CPU usage when the thread got switched in */
133      used = _Thread_Executing->cpu_time_used;
134
135      /* partial period, cpu usage info reset while executing.  Throw away */
136      if (_Timestamp_Less_than( &used, &the_period->owner_executed_at_period))
137        return;
138
139      /* How much time time since last context switch */
140      _Timestamp_Subtract(&_Thread_Time_of_last_context_switch, &uptime, &ran);
141
142      /* executed += ran */
143      _Timestamp_Add_to( &used, &ran );
144
145       /* executed = current cpu usage - value at start of period */
146      _Timestamp_Subtract(
147         &the_period->owner_executed_at_period,
148         &used,
149         &executed
150      );
151    }
152  #else
153      executed = the_period->owner->cpu_time_used -
154        the_period->owner_executed_at_period;
155  #endif
156
157  /*
158   *  Update CPU time
159   */
160
161  #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
162    _Timestamp_Add_to( &stats->total_cpu_time, &executed );
163
164    if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
165      stats->min_cpu_time = executed;
166
167    if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
168      stats->max_cpu_time = executed;
169  #else
170    stats->total_cpu_time  += executed;
171
172    if ( executed < stats->min_cpu_time )
173      stats->min_cpu_time = executed;
174
175    if ( executed > stats->max_cpu_time )
176      stats->max_cpu_time = executed;
177  #endif
178
179  /*
180   *  Update Wall time
181   */
182
183  #ifndef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
184    stats->total_wall_time += since_last_period;
185
186    if ( since_last_period < stats->min_wall_time )
187      stats->min_wall_time = since_last_period;
188
189    if ( since_last_period > stats->max_wall_time )
190      stats->max_wall_time = since_last_period;
191  #else
192    _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );
193
194    if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
195      stats->min_wall_time = since_last_period;
196
197    if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
198      stats->max_wall_time = since_last_period;
199  #endif
200}
201
202
203/*PAGE
204 *
205 *  rtems_rate_monotonic_period
206 *
207 *  This directive allows a thread to manipulate a rate monotonic timer.
208 *
209 *  Input parameters:
210 *    id     - rate monotonic id
211 *    length - length of period (in ticks)
212 *
213 *  Output parameters:
214 *    RTEMS_SUCCESSFUL - if successful
215 *    error code       - if unsuccessful
216 */
217
218rtems_status_code rtems_rate_monotonic_period(
219  Objects_Id        id,
220  rtems_interval    length
221)
222{
223  Rate_monotonic_Control              *the_period;
224  Objects_Locations                    location;
225  rtems_status_code                    return_value;
226  rtems_rate_monotonic_period_states   local_state;
227  ISR_Level                            level;
228
229  the_period = _Rate_monotonic_Get( id, &location );
230
231  switch ( location ) {
232    case OBJECTS_LOCAL:
233      if ( !_Thread_Is_executing( the_period->owner ) ) {
234        _Thread_Enable_dispatch();
235        return RTEMS_NOT_OWNER_OF_RESOURCE;
236      }
237
238      if ( length == RTEMS_PERIOD_STATUS ) {
239        switch ( the_period->state ) {
240          case RATE_MONOTONIC_INACTIVE:
241            return_value = RTEMS_NOT_DEFINED;
242            break;
243          case RATE_MONOTONIC_EXPIRED:
244          case RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING:
245            return_value = RTEMS_TIMEOUT;
246            break;
247          case RATE_MONOTONIC_ACTIVE:
248          default:              /* unreached -- only to remove warnings */
249            return_value = RTEMS_SUCCESSFUL;
250            break;
251        }
252        _Thread_Enable_dispatch();
253        return( return_value );
254      }
255
256      _ISR_Disable( level );
257      switch ( the_period->state ) {
258        case RATE_MONOTONIC_INACTIVE: {
259
260          _ISR_Enable( level );
261
262          /*
263           *  Baseline statistics information for the beginning of a period.
264           */
265          _Rate_monotonic_Initiate_statistics( the_period );
266
267          the_period->state = RATE_MONOTONIC_ACTIVE;
268          _Watchdog_Initialize(
269            &the_period->Timer,
270            _Rate_monotonic_Timeout,
271            id,
272            NULL
273          );
274
275          the_period->next_length = length;
276
277          _Watchdog_Insert_ticks( &the_period->Timer, length );
278          _Thread_Enable_dispatch();
279          return RTEMS_SUCCESSFUL;
280        }
281        case RATE_MONOTONIC_ACTIVE:
282
283          /*
284           *  Update statistics from the concluding period.
285           */
286          _Rate_monotonic_Update_statistics( the_period );
287
288          /*
289           *  This tells the _Rate_monotonic_Timeout that this task is
290           *  in the process of blocking on the period and that we
291           *  may be changing the length of the next period.
292           */
293          the_period->state = RATE_MONOTONIC_OWNER_IS_BLOCKING;
294          the_period->next_length = length;
295
296          _ISR_Enable( level );
297
298          _Thread_Executing->Wait.id = the_period->Object.id;
299          _Thread_Set_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD );
300
301          /*
302           *  Did the watchdog timer expire while we were actually blocking
303           *  on it?
304           */
305          _ISR_Disable( level );
306            local_state = the_period->state;
307            the_period->state = RATE_MONOTONIC_ACTIVE;
308          _ISR_Enable( level );
309
310          /*
311           *  If it did, then we want to unblock ourself and continue as
312           *  if nothing happen.  The period was reset in the timeout routine.
313           */
314          if ( local_state == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING )
315            _Thread_Clear_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD );
316
317          _Thread_Enable_dispatch();
318          return RTEMS_SUCCESSFUL;
319          break;
320
321        case RATE_MONOTONIC_EXPIRED:
322
323          /*
324           *  Update statistics from the concluding period
325           */
326          _Rate_monotonic_Update_statistics( the_period );
327
328          _ISR_Enable( level );
329
330          the_period->state = RATE_MONOTONIC_ACTIVE;
331          the_period->next_length = length;
332
333          _Watchdog_Insert_ticks( &the_period->Timer, length );
334          _Thread_Enable_dispatch();
335          return RTEMS_TIMEOUT;
336
337        case RATE_MONOTONIC_OWNER_IS_BLOCKING:
338        case RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING:
339          /*
340           *  These should never happen.
341           */
342          break;
343      }
344
345#if defined(RTEMS_MULTIPROCESSING)
346    case OBJECTS_REMOTE:            /* should never return this */
347#endif
348    case OBJECTS_ERROR:
349      break;
350  }
351
352  return RTEMS_INVALID_ID;
353}
Note: See TracBrowser for help on using the repository browser.