summaryrefslogtreecommitdiffstats
path: root/cpukit/libmisc/testsupport/testbusy.c
blob: 2d34a805dce3c4810648a8799ad223c5968e0e08 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*
 * Copyright (c) 2014, 2017 embedded brains GmbH.  All rights reserved.
 *
 *  embedded brains GmbH
 *  Dornierstr. 4
 *  82178 Puchheim
 *  Germany
 *  <rtems@embedded-brains.de>
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rtems.org/license/LICENSE.
 */


#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <rtems/test.h>
#include <rtems.h>

static uint_fast32_t estimate_busy_loop_maximum( void )
{
  uint_fast32_t units = 0;
  uint_fast32_t initial = rtems_clock_get_ticks_since_boot();

  while ( initial == rtems_clock_get_ticks_since_boot() ) {
    ++units;
  }

  return units;
}

static uint_fast32_t wait_for_tick_change( void )
{
  uint_fast32_t initial = rtems_clock_get_ticks_since_boot();
  uint_fast32_t now;

  do {
    now = rtems_clock_get_ticks_since_boot();
  } while ( now == initial );

  return now;
}

/*
 * It is important that we use actually use the same rtems_test_busy() function
 * at the various places, since otherwise the obtained maximum value might be
 * wrong.  So, the compiler must not inline this function.
 */
RTEMS_NO_INLINE void rtems_test_busy( uint_fast32_t count )
{
  uint_fast32_t i = 0;

  do {
    __asm__ volatile ("");
    ++i;
  } while ( i < count );
}

uint_fast32_t rtems_test_get_one_tick_busy_count( void )
{
  uint_fast32_t last;
  uint_fast32_t now;
  uint_fast32_t a;
  uint_fast32_t b;
  uint_fast32_t m;

  /* Choose a lower bound */
  a = 1;

  /* Estimate an upper bound */

  wait_for_tick_change();
  b = 2 * estimate_busy_loop_maximum();

  while ( true ) {
    last = wait_for_tick_change();
    rtems_test_busy( b );
    now = rtems_clock_get_ticks_since_boot();

    if ( now != last ) {
      break;
    }

    b *= 2;
    last = now;
  }

  /* Find a good value */
  do {
    m = ( a + b ) / 2;

    last = wait_for_tick_change();
    rtems_test_busy( m );
    now = rtems_clock_get_ticks_since_boot();

    if ( now != last ) {
      b = m;
    } else {
      a = m;
    }
  } while ( b - a > 1 );

  return m;
}