source: rtems/testsuites/sptests/spintrcritical_support/intrcritical.c @ 8028089

4.115
Last change on this file since 8028089 was 8028089, checked in by Sebastian Huber <sebastian.huber@…>, on 09/08/14 at 13:18:07

tests: Rework interrupt critical tests

This avoids test durations of more than one hour on fast targets, since
fast targets can count a lot during one clock tick period, so the minor
loop iteration count was quite high. Estimate now the test body
duration to iterate only through the interesting time window.

Add and use interrupt_critical_section_test().

  • Property mode set to 100644
File size: 5.3 KB
Line 
1/*
2 *  COPYRIGHT (c) 1989-2009.
3 *  On-Line Applications Research Corporation (OAR).
4 *
5 *  The license and distribution terms for this file may be
6 *  found in the file LICENSE in this distribution or at
7 *  http://www.rtems.org/license/LICENSE.
8 */
9
10#ifdef HAVE_CONFIG_H
11#include "config.h"
12#endif
13
14#include <tmacros.h>
15#include <intrcritical.h>
16
17#define INTERRUPT_CRITICAL_NAME rtems_build_name( 'I', 'C', 'R', 'I' )
18
19typedef struct {
20  rtems_interval minimum;
21  rtems_interval maximum;
22  rtems_interval maximum_current;
23  rtems_timer_service_routine_entry tsr;
24  rtems_id timer;
25  uint64_t t0;
26  uint64_t t1;
27} interrupt_critical_control;
28
29static interrupt_critical_control interrupt_critical;
30
31static rtems_interval estimate_busy_loop_maximum( void )
32{
33  rtems_interval units = 0;
34  rtems_interval initial = rtems_clock_get_ticks_since_boot();
35
36  while ( initial == rtems_clock_get_ticks_since_boot() ) {
37    ++units;
38  }
39
40  return units;
41}
42
43static rtems_interval wait_for_tick_change( void )
44{
45  rtems_interval initial = rtems_clock_get_ticks_since_boot();
46  rtems_interval now;
47
48  do {
49    now = rtems_clock_get_ticks_since_boot();
50  } while ( now == initial );
51
52  return now;
53}
54
55/*
56 * It is important that we use actually use the same busy() function at the
57 * various places, since otherwise the obtained maximum value might be wrong.
58 * So the compiler must not inline this function.
59 */
60static __attribute__( ( noinline ) ) void busy( rtems_interval max )
61{
62  rtems_interval i;
63
64  for ( i = 0; i < max; ++i ) {
65    __asm__ volatile ("");
66  }
67}
68
69static bool interrupt_critical_busy_wait( void )
70{
71  rtems_interval max = interrupt_critical.maximum_current;
72  bool reset = max <= interrupt_critical.minimum;
73
74  if ( reset ) {
75    interrupt_critical.maximum_current = interrupt_critical.maximum;
76  } else {
77    interrupt_critical.maximum_current = max - 1;
78  }
79
80  busy( max );
81
82  return reset;
83}
84
85void interrupt_critical_section_test_support_initialize(
86  rtems_timer_service_routine_entry tsr
87)
88{
89  rtems_interval last;
90  rtems_interval now;
91  rtems_interval a;
92  rtems_interval b;
93  rtems_interval m;
94
95  interrupt_critical.tsr = tsr;
96
97  if ( tsr != NULL && interrupt_critical.timer == 0 ) {
98    rtems_status_code sc = rtems_timer_create(
99      INTERRUPT_CRITICAL_NAME,
100      &interrupt_critical.timer
101    );
102    rtems_test_assert( sc == RTEMS_SUCCESSFUL );
103  }
104
105  /* Choose a lower bound */
106  a = 1;
107
108  /* Estimate an upper bound */
109
110  wait_for_tick_change();
111  b = 2 * estimate_busy_loop_maximum();
112
113  while ( true ) {
114    last = wait_for_tick_change();
115    busy( b );
116    now = rtems_clock_get_ticks_since_boot();
117
118    if ( now != last ) {
119      break;
120    }
121
122    b *= 2;
123    last = now;
124  }
125
126  /* Find a good value */
127  do {
128    m = ( a + b ) / 2;
129
130    last = wait_for_tick_change();
131    busy( m );
132    now = rtems_clock_get_ticks_since_boot();
133
134    if ( now != last ) {
135      b = m;
136    } else {
137      a = m;
138    }
139  } while ( b - a > 1 );
140
141  interrupt_critical.minimum = 0;
142  interrupt_critical.maximum = m;
143  interrupt_critical.maximum_current = m;
144}
145
146static void timer_fire_after(void)
147{
148  if ( interrupt_critical.tsr != NULL ) {
149    rtems_status_code sc = rtems_timer_fire_after(
150      interrupt_critical.timer,
151      1,
152      interrupt_critical.tsr,
153      NULL
154    );
155    rtems_test_assert( sc == RTEMS_SUCCESSFUL );
156  }
157}
158
159bool interrupt_critical_section_test_support_delay(void)
160{
161  timer_fire_after();
162
163  return interrupt_critical_busy_wait();
164}
165
166static bool is_idle( const Thread_Control *thread )
167{
168  return thread->Start.entry_point
169    == (Thread_Entry) rtems_configuration_get_idle_task();
170}
171
172static void thread_switch( Thread_Control *executing, Thread_Control *heir )
173{
174  (void) executing;
175  (void) heir;
176
177  if ( interrupt_critical.t1 == 0 && is_idle( heir ) ) {
178    interrupt_critical.t1 = rtems_clock_get_uptime_nanoseconds();
179  }
180}
181
182static const rtems_extensions_table extensions = {
183  .thread_switch = thread_switch
184};
185
186bool interrupt_critical_section_test(
187  bool                              ( *test_body )( void * ),
188  void                                *test_body_arg,
189  rtems_timer_service_routine_entry    tsr
190)
191{
192  bool done;
193  rtems_status_code sc;
194  rtems_id id;
195  uint64_t delta;
196  rtems_interval busy_delta;
197  int retries = 3;
198
199  interrupt_critical_section_test_support_initialize( tsr );
200
201  sc = rtems_extension_create(
202    INTERRUPT_CRITICAL_NAME,
203    &extensions,
204    &id
205  );
206  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
207
208  wait_for_tick_change();
209  timer_fire_after();
210
211  /* Get estimate for test body duration */
212  interrupt_critical.t0 = rtems_clock_get_uptime_nanoseconds();
213  done = ( *test_body )( test_body_arg );
214  if ( interrupt_critical.t1 == 0 ) {
215    interrupt_critical.t1 = rtems_clock_get_uptime_nanoseconds();
216  }
217
218  /* Update minimum */
219
220  delta = interrupt_critical.t1 - interrupt_critical.t0;
221  busy_delta = (rtems_interval)
222    ( ( interrupt_critical.maximum * ( 2 * delta ) )
223      / rtems_configuration_get_nanoseconds_per_tick() );
224
225  if ( busy_delta < interrupt_critical.maximum ) {
226    interrupt_critical.minimum = interrupt_critical.maximum - busy_delta;
227  }
228
229  sc = rtems_extension_delete( id );
230  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
231
232  while ( !done && retries >= 0 ) {
233    wait_for_tick_change();
234
235    if ( interrupt_critical_section_test_support_delay() ) {
236      --retries;
237    }
238
239    done = ( *test_body )( test_body_arg );
240  }
241
242  return done;
243}
Note: See TracBrowser for help on using the repository browser.