source: rtems/cpukit/rtems/src/ratemonperiod.c @ c2966871

4.104.115
Last change on this file since c2966871 was eb37f9d, checked in by Glenn Humphrey <glenn.humphrey@…>, on 12/08/09 at 23:05:30

2009-12-08 Glenn Humphrey <glenn.humphrey@…>

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